Cannot parse finishTime in SO responses 50/107750/2
authorJim Hahn <jrh3@att.com>
Fri, 15 May 2020 13:52:35 +0000 (09:52 -0400)
committerJim Hahn <jrh3@att.com>
Fri, 15 May 2020 15:53:17 +0000 (11:53 -0400)
The timestamp in SO responses appears to follow RFC-1123/RFC-822
format instead of ISO format.
Added a type adapter for SO.  In Guilin, we may want to consider
combining the two type adapters for LocalDateTime so that either format
is accepted.
Also modified the SO simulator to return responses that are actual
samples from SO.
As part of that work, discovered that the legacy SO actor is not able
to parse these timestamps either.  However, as that code is now
deprecated, left it as is.

Issue-ID: POLICY-2570
Change-Id: I322318d1007e36eef47bb8867fd8ed01cb60223a
Signed-off-by: Jim Hahn <jrh3@att.com>
models-interactions/model-actors/actor.so/src/main/java/org/onap/policy/controlloop/actor/so/SoOperation.java
models-interactions/model-actors/actor.so/src/test/java/org/onap/policy/controlloop/actor/so/BasicSoOperation.java
models-interactions/model-actors/actor.so/src/test/java/org/onap/policy/controlloop/actor/so/SoOperationTest.java
models-interactions/model-simulators/src/main/java/org/onap/policy/simulators/SoSimulatorJaxRs.java
models-interactions/model-simulators/src/main/resources/org/onap/policy/simulators/so/so.complete.success.json [new file with mode: 0644]
models-interactions/model-simulators/src/main/resources/org/onap/policy/simulators/so/so.started.json [new file with mode: 0644]
models-interactions/model-simulators/src/main/resources/org/onap/policy/simulators/so/so.still.running.json [new file with mode: 0644]
models-interactions/model-simulators/src/test/java/org/onap/policy/simulators/SoSimulatorTest.java

index a4c802c..2a00edd 100644 (file)
 
 package org.onap.policy.controlloop.actor.so;
 
+import com.google.gson.Gson;
+import com.google.gson.GsonBuilder;
+import com.google.gson.JsonParseException;
+import com.google.gson.TypeAdapter;
+import com.google.gson.stream.JsonReader;
+import com.google.gson.stream.JsonToken;
+import com.google.gson.stream.JsonWriter;
+import java.io.IOException;
+import java.time.LocalDateTime;
+import java.time.format.DateTimeFormatter;
+import java.time.format.DateTimeParseException;
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.List;
@@ -39,9 +50,11 @@ import org.onap.policy.aai.AaiConstants;
 import org.onap.policy.aai.AaiCqResponse;
 import org.onap.policy.common.endpoints.event.comm.Topic.CommInfrastructure;
 import org.onap.policy.common.endpoints.utils.NetLoggerUtil.EventType;
+import org.onap.policy.common.gson.GsonMessageBodyHandler;
 import org.onap.policy.common.utils.coder.Coder;
 import org.onap.policy.common.utils.coder.CoderException;
 import org.onap.policy.common.utils.coder.StandardCoder;
+import org.onap.policy.common.utils.coder.StandardCoderObject;
 import org.onap.policy.controlloop.actorserviceprovider.OperationOutcome;
 import org.onap.policy.controlloop.actorserviceprovider.impl.HttpOperation;
 import org.onap.policy.controlloop.actorserviceprovider.parameters.ControlLoopOperationParams;
@@ -64,7 +77,7 @@ import org.slf4j.LoggerFactory;
  */
 public abstract class SoOperation extends HttpOperation<SoResponse> {
     private static final Logger logger = LoggerFactory.getLogger(SoOperation.class);
-    private static final Coder coder = new StandardCoder();
+    private static final Coder coder = new SoCoder();
 
     public static final String PAYLOAD_KEY_VF_COUNT = "vfCount";
     public static final String FAILED = "FAILED";
@@ -479,4 +492,74 @@ public abstract class SoOperation extends HttpOperation<SoResponse> {
     public int getWaitSecGet() {
         return config.getWaitSecGet();
     }
+
+    @Override
+    protected Coder makeCoder() {
+        return coder;
+    }
+
+    /*
+     * TODO: combine this adapter with existing LocalDateTimeTypeAdapter and eliminate the
+     * following two classes.
+     */
+
+    /**
+     * GSON Type Adapter for "LocalDateTime" fields, that uses the standard
+     * RFC_1123_DATE_TIME formatter.
+     */
+    private static class SoLocalDateTimeTypeAdapter extends TypeAdapter<LocalDateTime> {
+        private static final DateTimeFormatter FORMATTER = DateTimeFormatter.RFC_1123_DATE_TIME;
+
+        @Override
+        public LocalDateTime read(JsonReader in) throws IOException {
+            try {
+                if (in.peek() == JsonToken.NULL) {
+                    in.nextNull();
+                    return null;
+                } else {
+                    return LocalDateTime.parse(in.nextString(), FORMATTER);
+                }
+
+            } catch (DateTimeParseException e) {
+                throw new JsonParseException("invalid date", e);
+            }
+        }
+
+        @Override
+        public void write(JsonWriter out, LocalDateTime value) throws IOException {
+            if (value == null) {
+                out.nullValue();
+            } else {
+                String text = value.format(FORMATTER);
+                out.value(text);
+            }
+        }
+    }
+
+    private static class SoCoder extends StandardCoder {
+
+        /**
+         * Gson object used to encode and decode messages.
+         */
+        private static final Gson SO_GSON;
+
+        /**
+         * Gson object used to encode messages in "pretty" format.
+         */
+        private static final Gson SO_GSON_PRETTY;
+
+        static {
+            GsonBuilder builder = GsonMessageBodyHandler
+                            .configBuilder(new GsonBuilder().registerTypeAdapter(StandardCoderObject.class,
+                                            new StandardTypeAdapter()))
+                            .registerTypeAdapter(LocalDateTime.class, new SoLocalDateTimeTypeAdapter());
+
+            SO_GSON = builder.create();
+            SO_GSON_PRETTY = builder.setPrettyPrinting().create();
+        }
+
+        public SoCoder() {
+            super(SO_GSON, SO_GSON_PRETTY);
+        }
+    }
 }
index 0232226..aaecb46 100644 (file)
@@ -96,11 +96,11 @@ public abstract class BasicSoOperation extends BasicHttpOperation<SoRequest> {
                         .serializationProvider(GsonMessageBodyHandler.class.getName()).build();
         HttpClientFactoryInstance.getClientFactory().build(clientParams);
 
-        SoSimulatorJaxRs.setYieldIncomplete(true);
+        SoSimulatorJaxRs.setRequirePolling(true);
     }
 
     protected static void destroyAfterClass() {
-        SoSimulatorJaxRs.setYieldIncomplete(false);
+        SoSimulatorJaxRs.setRequirePolling(false);
         HttpClientFactoryInstance.getClientFactory().destroy();
         HttpServletServerFactoryInstance.getServerFactory().destroy();
     }
index 7009396..6445218 100644 (file)
@@ -32,6 +32,8 @@ import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.when;
 
+import java.time.LocalDateTime;
+import java.time.Month;
 import java.util.Collections;
 import java.util.List;
 import java.util.concurrent.CompletableFuture;
@@ -46,6 +48,7 @@ import org.onap.aai.domain.yang.GenericVnf;
 import org.onap.aai.domain.yang.ServiceInstance;
 import org.onap.aai.domain.yang.Tenant;
 import org.onap.policy.aai.AaiCqResponse;
+import org.onap.policy.common.utils.coder.Coder;
 import org.onap.policy.common.utils.coder.CoderException;
 import org.onap.policy.controlloop.ControlLoopOperation;
 import org.onap.policy.controlloop.actorserviceprovider.OperationOutcome;
@@ -422,4 +425,18 @@ public class SoOperationTest extends BasicSoOperation {
         when(cq.getDefaultCloudRegion()).thenReturn(region);
         assertSame(region, oper.getDefaultCloudRegion(cq));
     }
+
+    @Test
+    public void testMakeCoder() throws CoderException {
+        Coder opcoder = oper.makeCoder();
+
+        // ensure we can decode an SO timestamp
+        String json = "{'request':{'finishTime':'Fri, 15 May 2020 12:14:21 GMT'}}";
+        SoResponse resp = opcoder.decode(json.replace('\'', '"'), SoResponse.class);
+
+        LocalDateTime tfinish = resp.getRequest().getFinishTime();
+        assertNotNull(tfinish);
+        assertEquals(2020, tfinish.getYear());
+        assertEquals(Month.MAY, tfinish.getMonth());
+    }
 }
index 8e787f8..d83f5a5 100644 (file)
@@ -33,24 +33,19 @@ import javax.ws.rs.PathParam;
 import javax.ws.rs.Produces;
 import javax.ws.rs.core.MediaType;
 import lombok.Setter;
-import org.onap.policy.common.utils.coder.Coder;
-import org.onap.policy.common.utils.coder.CoderException;
-import org.onap.policy.common.utils.coder.StandardCoder;
-import org.onap.policy.so.SoRequest;
-import org.onap.policy.so.SoRequestReferences;
-import org.onap.policy.so.SoRequestStatus;
-import org.onap.policy.so.SoResponse;
+import org.onap.policy.common.utils.resources.ResourceUtils;
 
 
 @Path("/")
 public class SoSimulatorJaxRs {
-    private final Coder coder = new StandardCoder();
+
+    private static final String REPLACE_ME = "${replaceMe}";
 
     /**
      * Set of incomplete request IDs. When a POST or DELETE is performed, the new request
-     * ID is added to the set. When the request is polled, the ID is removed and an empty
-     * response is returned. When the request is polled again, it sees that there is no
-     * entry and returns a completion indication.
+     * ID is added to the set. When the request is polled, the ID is removed and a "still
+     * running" response is returned. When the request is polled again, it sees that there
+     * is no entry and returns a completion indication.
      *
      * <p/>
      * This is static so request IDs are retained across servlets.
@@ -58,11 +53,11 @@ public class SoSimulatorJaxRs {
     private static final Set<String> incomplete = ConcurrentHashMap.newKeySet();
 
     /**
-     * {@code True} if the initial request should yield an incomplete, {@code false}
+     * {@code True} if requests should require polling, {@code false}
      * otherwise.  This is used when junit testing the SO actor.
      */
     @Setter
-    private static boolean yieldIncomplete = false;
+    private static boolean requirePolling = false;
 
     /**
      * SO post query.
@@ -76,9 +71,9 @@ public class SoSimulatorJaxRs {
     @Consumes(MediaType.APPLICATION_JSON)
     @Produces("application/json")
     public String soPostQuery(@PathParam("serviceInstanceId") final String serviceInstanceId,
-                    @PathParam("vnfInstanceId") final String vnfInstanceId) throws CoderException {
+                    @PathParam("vnfInstanceId") final String vnfInstanceId) {
 
-        return coder.encode(yieldIncomplete ? makeIncomplete() : makeComplete(UUID.randomUUID().toString()));
+        return (requirePolling ? makeStarted() : makeComplete(UUID.randomUUID().toString()));
     }
 
     /**
@@ -94,9 +89,9 @@ public class SoSimulatorJaxRs {
     @Produces("application/json")
     public String soDelete(@PathParam("serviceInstanceId") final String serviceInstanceId,
                     @PathParam("vnfInstanceId") final String vnfInstanceId,
-                    @PathParam("vfModuleInstanceId") final String vfModuleInstanceId) throws CoderException {
+                    @PathParam("vfModuleInstanceId") final String vfModuleInstanceId) {
 
-        return coder.encode(yieldIncomplete ? makeIncomplete() : makeComplete(UUID.randomUUID().toString()));
+        return (requirePolling ? makeStarted() : makeComplete(UUID.randomUUID().toString()));
     }
 
     /**
@@ -109,49 +104,33 @@ public class SoSimulatorJaxRs {
     @Path("/orchestrationRequests/v5/{requestId}")
     @Consumes(MediaType.APPLICATION_JSON)
     @Produces("application/json")
-    public String soGetQuery(@PathParam("requestId") final String requestId) throws CoderException {
+    public String soGetQuery(@PathParam("requestId") final String requestId) {
         if (incomplete.remove(requestId)) {
-            // first poll - return empty response
-            return coder.encode(new SoResponse());
+            // first poll - return "still running"
+            return makeStillRunning(requestId);
 
         } else {
-            return coder.encode(makeComplete(requestId));
+            return makeComplete(requestId);
         }
     }
 
-    private SoResponse makeIncomplete() {
-        final SoResponse response = makeResponse();
-        response.getRequest().getRequestStatus().setRequestState("INCOMPLETE");
-
-        incomplete.add(response.getRequestReferences().getRequestId());
-
-        return response;
-    }
+    private String makeStarted() {
+        String requestId = UUID.randomUUID().toString();
 
-    private SoResponse makeComplete(String requestId) {
-        final SoResponse response = makeResponse();
+        String response = ResourceUtils.getResourceAsString("org/onap/policy/simulators/so/so.started.json");
 
-        response.getRequest().getRequestStatus().setRequestState("COMPLETE");
-        response.getRequest().setRequestId(UUID.fromString(requestId));
+        incomplete.add(requestId);
 
-        return response;
+        return response.replace(REPLACE_ME, requestId);
     }
 
-    private SoResponse makeResponse() {
-        final SoRequest request = new SoRequest();
-        final SoRequestStatus requestStatus = new SoRequestStatus();
-        request.setRequestStatus(requestStatus);
-        request.setRequestId(UUID.randomUUID());
-
-        final SoResponse response = new SoResponse();
-
-        final SoRequestReferences requestReferences = new SoRequestReferences();
-        final String requestId = UUID.randomUUID().toString();
-        requestReferences.setRequestId(requestId);
-        response.setRequestReferences(requestReferences);
-
-        response.setRequest(request);
+    private String makeComplete(String requestId) {
+        String response = ResourceUtils.getResourceAsString("org/onap/policy/simulators/so/so.complete.success.json");
+        return response.replace(REPLACE_ME, requestId);
+    }
 
-        return response;
+    private String makeStillRunning(String requestId) {
+        String response = ResourceUtils.getResourceAsString("org/onap/policy/simulators/so/so.still.running.json");
+        return response.replace(REPLACE_ME, requestId);
     }
 }
diff --git a/models-interactions/model-simulators/src/main/resources/org/onap/policy/simulators/so/so.complete.success.json b/models-interactions/model-simulators/src/main/resources/org/onap/policy/simulators/so/so.complete.success.json
new file mode 100644 (file)
index 0000000..7a5892e
--- /dev/null
@@ -0,0 +1,87 @@
+{
+    "request": {
+        "requestId": "${replaceMe}",
+        "startTime": "Fri, 15 May 2020 12:12:50 GMT",
+        "finishTime": "Fri, 15 May 2020 12:14:21 GMT",
+        "requestScope": "vfModule",
+        "requestType": "scaleOut",
+        "requestDetails": {
+            "modelInfo": {
+                "modelInvariantId": "2246ebc9-9b9f-42d0-a5e4-0248324fb884",
+                "modelType": "vfModule",
+                "modelName": "VlbCdsSb00..vdns..module-3",
+                "modelVersion": "1",
+                "modelCustomizationUuid": "3a74410a-6c74-4a32-94b2-71488be6da1a",
+                "modelVersionId": "1f94cedb-f656-4ddb-9f55-60ba1fc7d4b1",
+                "modelCustomizationId": "3a74410a-6c74-4a32-94b2-71488be6da1a",
+                "modelUuid": "1f94cedb-f656-4ddb-9f55-60ba1fc7d4b1",
+                "modelInvariantUuid": "2246ebc9-9b9f-42d0-a5e4-0248324fb884"
+            },
+            "requestInfo": {
+                "source": "POLICY",
+                "instanceName": "vfModuleName",
+                "suppressRollback": false,
+                "requestorId": "policy"
+            },
+            "relatedInstanceList": [
+                {
+                    "relatedInstance": {
+                        "instanceId": "c14e61b5-1ee6-4925-b4a9-b9c8dbfe3f34",
+                        "modelInfo": {
+                            "modelInvariantId": "6418bb39-61e1-45fc-a36b-3f211bb846c7",
+                            "modelType": "service",
+                            "modelName": "vLB_CDS_SB00_02",
+                            "modelVersion": "1.0",
+                            "modelVersionId": "d01d9dec-afb6-4a53-bd9e-2eb10ca07a51",
+                            "modelUuid": "d01d9dec-afb6-4a53-bd9e-2eb10ca07a51",
+                            "modelInvariantUuid": "6418bb39-61e1-45fc-a36b-3f211bb846c7"
+                        }
+                    }
+                },
+                {
+                    "relatedInstance": {
+                        "instanceId": "6636c4d5-f608-4376-b6d8-7977e98cb16d",
+                        "modelInfo": {
+                            "modelInvariantId": "827356a9-cb60-4976-9713-c30b4f850b41",
+                            "modelType": "vnf",
+                            "modelName": "vLB_CDS_SB00",
+                            "modelVersion": "1.0",
+                            "modelCustomizationUuid": "6478f94b-0b20-4b44-afc0-94e48070586a",
+                            "modelVersionId": "ca3c4797-0cdd-4797-8bec-9a3ce78ac4da",
+                            "modelCustomizationId": "6478f94b-0b20-4b44-afc0-94e48070586a",
+                            "modelUuid": "ca3c4797-0cdd-4797-8bec-9a3ce78ac4da",
+                            "modelInvariantUuid": "827356a9-cb60-4976-9713-c30b4f850b41"
+                        }
+                    }
+                }
+            ],
+            "cloudConfiguration": {
+                "tenantId": "41d6d38489bd40b09ea8a6b6b852dcbd",
+                "tenantName": "Integration-SB-00",
+                "cloudOwner": "CloudOwner",
+                "lcpCloudRegionId": "RegionOne"
+            },
+            "requestParameters": {
+                "usePreload": false
+            },
+            "configurationParameters": [
+                {
+                    "ip-addr": "$.vf-module-topology.vf-module-parameters.param[16].value",
+                    "oam-ip-addr": "$.vf-module-topology.vf-module-parameters.param[30].value"
+                }
+            ]
+        },
+        "instanceReferences": {
+            "serviceInstanceId": "c14e61b5-1ee6-4925-b4a9-b9c8dbfe3f34",
+            "vnfInstanceId": "6636c4d5-f608-4376-b6d8-7977e98cb16d",
+            "vfModuleInstanceId": "68804843-18e0-41a3-8838-a6d90a035e1a",
+            "vfModuleInstanceName": "vfModuleName"
+        },
+        "requestStatus": {
+            "requestState": "COMPLETE",
+            "statusMessage": "STATUS: ALaCarte-VfModule-scaleOut request was executed correctly. FLOW STATUS: Successfully completed all Building Blocks RESOURCE STATUS: The vf module was found to already exist, thus no new vf module was created in the cloud via this request",
+            "percentProgress": 100,
+            "timestamp": "Fri, 15 May 2020 12:14:21 GMT"
+        }
+    }
+}
diff --git a/models-interactions/model-simulators/src/main/resources/org/onap/policy/simulators/so/so.started.json b/models-interactions/model-simulators/src/main/resources/org/onap/policy/simulators/so/so.started.json
new file mode 100644 (file)
index 0000000..eac381b
--- /dev/null
@@ -0,0 +1,7 @@
+{
+    "requestReferences": {
+        "requestId": "${replaceMe}",
+        "instanceId": "68804843-18e0-41a3-8838-a6d90a035e1a",
+        "requestSelfLink": "http://so.onap:8080/orchestrationRequests/v7/b789e4e6-0b92-42c3-a723-1879af9c799d"
+    }
+}
diff --git a/models-interactions/model-simulators/src/main/resources/org/onap/policy/simulators/so/so.still.running.json b/models-interactions/model-simulators/src/main/resources/org/onap/policy/simulators/so/so.still.running.json
new file mode 100644 (file)
index 0000000..077b15d
--- /dev/null
@@ -0,0 +1,86 @@
+{
+    "request": {
+        "requestId": "${replaceMe}",
+        "startTime": "Fri, 15 May 2020 12:12:50 GMT",
+        "requestScope": "vfModule",
+        "requestType": "scaleOut",
+        "requestDetails": {
+            "modelInfo": {
+                "modelInvariantId": "2246ebc9-9b9f-42d0-a5e4-0248324fb884",
+                "modelType": "vfModule",
+                "modelName": "VlbCdsSb00..vdns..module-3",
+                "modelVersion": "1",
+                "modelCustomizationUuid": "3a74410a-6c74-4a32-94b2-71488be6da1a",
+                "modelVersionId": "1f94cedb-f656-4ddb-9f55-60ba1fc7d4b1",
+                "modelCustomizationId": "3a74410a-6c74-4a32-94b2-71488be6da1a",
+                "modelUuid": "1f94cedb-f656-4ddb-9f55-60ba1fc7d4b1",
+                "modelInvariantUuid": "2246ebc9-9b9f-42d0-a5e4-0248324fb884"
+            },
+            "requestInfo": {
+                "source": "POLICY",
+                "instanceName": "vfModuleName",
+                "suppressRollback": false,
+                "requestorId": "policy"
+            },
+            "relatedInstanceList": [
+                {
+                    "relatedInstance": {
+                        "instanceId": "c14e61b5-1ee6-4925-b4a9-b9c8dbfe3f34",
+                        "modelInfo": {
+                            "modelInvariantId": "6418bb39-61e1-45fc-a36b-3f211bb846c7",
+                            "modelType": "service",
+                            "modelName": "vLB_CDS_SB00_02",
+                            "modelVersion": "1.0",
+                            "modelVersionId": "d01d9dec-afb6-4a53-bd9e-2eb10ca07a51",
+                            "modelUuid": "d01d9dec-afb6-4a53-bd9e-2eb10ca07a51",
+                            "modelInvariantUuid": "6418bb39-61e1-45fc-a36b-3f211bb846c7"
+                        }
+                    }
+                },
+                {
+                    "relatedInstance": {
+                        "instanceId": "6636c4d5-f608-4376-b6d8-7977e98cb16d",
+                        "modelInfo": {
+                            "modelInvariantId": "827356a9-cb60-4976-9713-c30b4f850b41",
+                            "modelType": "vnf",
+                            "modelName": "vLB_CDS_SB00",
+                            "modelVersion": "1.0",
+                            "modelCustomizationUuid": "6478f94b-0b20-4b44-afc0-94e48070586a",
+                            "modelVersionId": "ca3c4797-0cdd-4797-8bec-9a3ce78ac4da",
+                            "modelCustomizationId": "6478f94b-0b20-4b44-afc0-94e48070586a",
+                            "modelUuid": "ca3c4797-0cdd-4797-8bec-9a3ce78ac4da",
+                            "modelInvariantUuid": "827356a9-cb60-4976-9713-c30b4f850b41"
+                        }
+                    }
+                }
+            ],
+            "cloudConfiguration": {
+                "tenantId": "41d6d38489bd40b09ea8a6b6b852dcbd",
+                "tenantName": "Integration-SB-00",
+                "cloudOwner": "CloudOwner",
+                "lcpCloudRegionId": "RegionOne"
+            },
+            "requestParameters": {
+                "usePreload": false
+            },
+            "configurationParameters": [
+                {
+                    "ip-addr": "$.vf-module-topology.vf-module-parameters.param[16].value",
+                    "oam-ip-addr": "$.vf-module-topology.vf-module-parameters.param[30].value"
+                }
+            ]
+        },
+        "instanceReferences": {
+            "serviceInstanceId": "c14e61b5-1ee6-4925-b4a9-b9c8dbfe3f34",
+            "vnfInstanceId": "6636c4d5-f608-4376-b6d8-7977e98cb16d",
+            "vfModuleInstanceId": "68804843-18e0-41a3-8838-a6d90a035e1a",
+            "vfModuleInstanceName": "vfModuleName"
+        },
+        "requestStatus": {
+            "requestState": "IN_PROGRESS",
+            "statusMessage": "FLOW STATUS: Execution of ActivateVfModuleBB has completed successfully, next invoking ConfigurationScaleOutBB (Execution Path progress: BBs completed = 4; BBs remaining = 2). TASK INFORMATION: Last task executed: Call SDNC RESOURCE STATUS: The vf module was found to already exist, thus no new vf module was created in the cloud via this request",
+            "percentProgress": 68,
+            "timestamp": "Fri, 15 May 2020 12:13:41 GMT"
+        }
+    }
+}
index c5f9973..d8613c8 100644 (file)
@@ -21,9 +21,9 @@
 
 package org.onap.policy.simulators;
 
-import static org.junit.Assert.assertEquals;
+import static org.assertj.core.api.Assertions.assertThat;
 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.util.HashMap;
@@ -42,7 +42,6 @@ import org.onap.policy.so.SoRequest;
 import org.onap.policy.so.SoRequestDetails;
 import org.onap.policy.so.SoRequestInfo;
 import org.onap.policy.so.SoRequestParameters;
-import org.onap.policy.so.SoResponse;
 import org.onap.policy.so.util.Serialization;
 
 public class SoSimulatorTest {
@@ -62,7 +61,7 @@ public class SoSimulatorTest {
     @AfterClass
     public static void tearDownSimulator() {
         HttpServletServerFactoryInstance.getServerFactory().destroy();
-        SoSimulatorJaxRs.setYieldIncomplete(false);
+        SoSimulatorJaxRs.setRequirePolling(false);
     }
 
     /**
@@ -138,23 +137,19 @@ public class SoSimulatorTest {
 
     @Test
     public void testPost() {
-        SoSimulatorJaxRs.setYieldIncomplete(false);
+        SoSimulatorJaxRs.setRequirePolling(false);
         String request = Serialization.gsonPretty.toJson(this.createTestRequest());
         Pair<Integer, String> httpDetails = new RestManager().post(
                         "http://localhost:6667/serviceInstantiation/v7/serviceInstances/12345/vnfs/12345/vfModules/scaleOut",
                         "username",
                         "password", new HashMap<>(), "application/json", request);
         assertNotNull(httpDetails);
-        SoResponse response = Serialization.gsonPretty.fromJson(httpDetails.second, SoResponse.class);
-        assertNotNull(response);
-        assertNotNull(response.getRequestReferences());
-        assertNotNull(response.getRequestReferences().getRequestId());
-        assertEquals("COMPLETE", response.getRequest().getRequestStatus().getRequestState());
+        assertThat(httpDetails.second).contains("\"COMPLETE\"").doesNotContain("requestSelfLink");
 
         /*
          * Repeat, but set the flag indicating that the request should yield incomplete.
          */
-        SoSimulatorJaxRs.setYieldIncomplete(true);
+        SoSimulatorJaxRs.setRequirePolling(true);
 
         request = Serialization.gsonPretty.toJson(this.createTestRequest());
         httpDetails = new RestManager().post(
@@ -162,55 +157,41 @@ public class SoSimulatorTest {
                         "username",
                         "password", new HashMap<>(), "application/json", request);
         assertNotNull(httpDetails);
-        response = Serialization.gsonPretty.fromJson(httpDetails.second, SoResponse.class);
-        assertNotNull(response);
-        assertNotNull(response.getRequestReferences());
-        assertNotNull(response.getRequestReferences().getRequestId());
-        assertEquals("INCOMPLETE", response.getRequest().getRequestStatus().getRequestState());
+        assertThat(httpDetails.second).contains("requestSelfLink").doesNotContain("\"COMPLETE\"");
 
         // now poll for the response
-        String reqid = response.getRequestReferences().getRequestId();
+        String uri = extractUri(httpDetails.second);
         httpDetails = new RestManager().get(
-                        "http://localhost:6667//orchestrationRequests/v5/" + reqid,
+                        "http://localhost:6667/orchestrationRequests/v5/" + uri,
                         "username",
                         "password", new HashMap<>());
         assertNotNull(httpDetails);
-        response = Serialization.gsonPretty.fromJson(httpDetails.second, SoResponse.class);
-        assertNotNull(response);
-        assertNull(response.getRequest());
+        assertThat(httpDetails.second).contains("\"IN_PROGRESS\"").doesNotContain("requestSelfLink");
 
         // poll again
         httpDetails = new RestManager().get(
-                        "http://localhost:6667//orchestrationRequests/v5/" + reqid,
+                        "http://localhost:6667/orchestrationRequests/v5/" + uri,
                         "username",
                         "password", new HashMap<>());
         assertNotNull(httpDetails);
-        response = Serialization.gsonPretty.fromJson(httpDetails.second, SoResponse.class);
-        assertNotNull(response);
-        assertNotNull(response.getRequest());
-        assertNotNull(response.getRequest().getRequestStatus());
-        assertEquals("COMPLETE", response.getRequest().getRequestStatus().getRequestState());
+        assertThat(httpDetails.second).contains("\"COMPLETE\"").doesNotContain("requestSelfLink");
     }
 
     @Test
     public void testDelete() {
-        SoSimulatorJaxRs.setYieldIncomplete(false);
+        SoSimulatorJaxRs.setRequirePolling(false);
         String request = Serialization.gsonPretty.toJson(this.createTestRequest());
         Pair<Integer, String> httpDetails = new RestManager().delete(
                         "http://localhost:6667/serviceInstances/v7/12345/vnfs/12345/vfModules/12345",
                         "username",
                         "password", new HashMap<>(), "application/json", request);
         assertNotNull(httpDetails);
-        SoResponse response = Serialization.gsonPretty.fromJson(httpDetails.second, SoResponse.class);
-        assertNotNull(response);
-        assertNotNull(response.getRequestReferences());
-        assertNotNull(response.getRequestReferences().getRequestId());
-        assertEquals("COMPLETE", response.getRequest().getRequestStatus().getRequestState());
+        assertThat(httpDetails.second).contains("\"COMPLETE\"").doesNotContain("requestSelfLink");
 
         /*
          * Repeat, but set the flag indicating that the request should yield incomplete.
          */
-        SoSimulatorJaxRs.setYieldIncomplete(true);
+        SoSimulatorJaxRs.setRequirePolling(true);
 
         request = Serialization.gsonPretty.toJson(this.createTestRequest());
         httpDetails = new RestManager().delete(
@@ -218,33 +199,37 @@ public class SoSimulatorTest {
                         "username",
                         "password", new HashMap<>(), "application/json", request);
         assertNotNull(httpDetails);
-        response = Serialization.gsonPretty.fromJson(httpDetails.second, SoResponse.class);
-        assertNotNull(response);
-        assertNotNull(response.getRequestReferences());
-        assertNotNull(response.getRequestReferences().getRequestId());
-        assertEquals("INCOMPLETE", response.getRequest().getRequestStatus().getRequestState());
+        assertThat(httpDetails.second).contains("requestSelfLink").doesNotContain("\"COMPLETE\"");
 
         // now poll for the response
-        String reqid = response.getRequestReferences().getRequestId();
+        String uri = extractUri(httpDetails.second);
         httpDetails = new RestManager().get(
-                        "http://localhost:6667//orchestrationRequests/v5/" + reqid,
+                        "http://localhost:6667/orchestrationRequests/v5/" + uri,
                         "username",
                         "password", new HashMap<>());
         assertNotNull(httpDetails);
-        response = Serialization.gsonPretty.fromJson(httpDetails.second, SoResponse.class);
-        assertNotNull(response);
-        assertNull(response.getRequest());
+        assertThat(httpDetails.second).contains("\"IN_PROGRESS\"").doesNotContain("requestSelfLink");
 
         // poll again
         httpDetails = new RestManager().get(
-                        "http://localhost:6667//orchestrationRequests/v5/" + reqid,
+                        "http://localhost:6667/orchestrationRequests/v5/" + uri,
                         "username",
                         "password", new HashMap<>());
         assertNotNull(httpDetails);
-        response = Serialization.gsonPretty.fromJson(httpDetails.second, SoResponse.class);
-        assertNotNull(response);
-        assertNotNull(response.getRequest());
-        assertNotNull(response.getRequest().getRequestStatus());
-        assertEquals("COMPLETE", response.getRequest().getRequestStatus().getRequestState());
+        assertThat(httpDetails.second).contains("\"COMPLETE\"").doesNotContain("requestSelfLink");
+    }
+
+    private String extractUri(String response) {
+        final String prefix = "\"requestId\": \"";
+
+        int start = response.indexOf(prefix);
+        assertTrue(start >= 0);
+
+        start += prefix.length();
+
+        int end = response.indexOf('"', start);
+        assertTrue(end >= 0);
+
+        return response.substring(start, end);
     }
 }