Handle embedded "<" in SDNC responses 77/21377/1
authorJim Hahn <jrh3@att.com>
Mon, 30 Oct 2017 19:58:19 +0000 (15:58 -0400)
committerJim Hahn <jrh3@att.com>
Mon, 30 Oct 2017 19:58:19 +0000 (15:58 -0400)
Modified the code to use an actual XML parser when decoding the SDNC
response-data element, instead of using the simple-minded
replace("&amp;", "&") approach.  The latter did not function correctly
when XML elements contained other xml-encoded data.

Change-Id: Ied6b8b19f307f728b8da1a2b410b9e239ec62ab6
Issue-Id: SO-115
Signed-off-by: Jim Hahn <jrh3@att.com>
bpmn/MSOCommonBPMN/src/main/groovy/org/openecomp/mso/bpmn/common/scripts/SDNCAdapterUtils.groovy
bpmn/MSOCommonBPMN/src/test/groovy/org/openecomp/mso/bpmn/common/scripts/SDNCAdapterUtilsTest.groovy [new file with mode: 0644]

index b356166..c43f884 100644 (file)
@@ -24,7 +24,7 @@ import org.apache.commons.lang3.*
 import org.camunda.bpm.engine.delegate.BpmnError\r
 import org.camunda.bpm.engine.runtime.Execution\r
 import org.openecomp.mso.bpmn.core.WorkflowException\r
-import org.openecomp.mso.bpmn.core.json.JsonUtils;\r
+import org.openecomp.mso.bpmn.core.json.JsonUtils\r
 import org.springframework.web.util.UriUtils\r
 \r
 \r
@@ -730,13 +730,8 @@ class SDNCAdapterUtils {
                                        taskProcessor.utils.log("DEBUG", response + ' is empty');\r
                                        exceptionUtil.buildAndThrowWorkflowException(execution, 500, "SDNCAdapter Workflow Response is Empty")\r
                                }else{\r
-\r
                                        // we need to peer into the request data for error\r
-                                       def String sdncAdapterWorkflowResponse = taskProcessor.utils.getNodeXml(response, 'response-data', false)\r
-                                       def String decodedXml = decodeXML(sdncAdapterWorkflowResponse).replace('<?xml version="1.0" encoding="UTF-8"?>', "")\r
-\r
-                                       // change '&' to "&amp; (if present as data, ex: subscriber-name = 'FOUR SEASONS HEATING & COOLING_8310006378683'\r
-                                       decodedXml = decodedXml.replace("&", "&amp;")\r
+                                       def String decodedXml = taskProcessor.utils.getNodeText1(response, "RequestData")\r
 \r
                                        taskProcessor.utils.log("DEBUG","decodedXml:\n" + decodedXml, isDebugLogEnabled)\r
 \r
@@ -745,12 +740,14 @@ class SDNCAdapterUtils {
 \r
                                        try{\r
                                                if (taskProcessor.utils.nodeExists(decodedXml, "response-message")) {\r
-                                                       requestDataResponseMessage = taskProcessor.utils.getNodeText(decodedXml, "response-message")\r
-                                               } else if (taskProcessor.utils.nodeExists(decodedXml, "ResponseMessage")) {\r
-                                                       requestDataResponseMessage = taskProcessor.utils.getNodeText(decodedXml, "ResponseMessage")\r
+                                                       requestDataResponseMessage = taskProcessor.utils.getNodeText1(decodedXml, "response-message")\r
+                                                       \r
+                                                       // note: ResponseMessage appears within "response", not "decodedXml"\r
+                                               } else if (taskProcessor.utils.nodeExists(response, "ResponseMessage")) {\r
+                                                       requestDataResponseMessage = taskProcessor.utils.getNodeText1(response, "ResponseMessage")\r
                                                }\r
                                        }catch(Exception e){\r
-                                               taskProcessor.utils.log("DEBUG", 'Error caught while decoding resposne ' + e.getMessage(), isDebugLogEnabled)\r
+                                               taskProcessor.utils.log("DEBUG", 'Error caught while decoding response ' + e.getMessage(), isDebugLogEnabled)\r
                                        }\r
 \r
                                        if(taskProcessor.utils.nodeExists(decodedXml, "response-code")) {\r
@@ -761,18 +758,20 @@ class SDNCAdapterUtils {
                                                        taskProcessor.utils.log("DEBUG","response-code node is empty", isDebugLogEnabled)\r
                                                        requestDataResponseCode = 0\r
                                                }else{\r
-                                                       requestDataResponseCode  = code.toInteger()\r
+                                                       requestDataResponseCode  = code as Integer\r
                                                        taskProcessor.utils.log("DEBUG","response-code is: " + requestDataResponseCode, isDebugLogEnabled)\r
                                                }\r
-                                       }else if(taskProcessor.utils.nodeExists(decodedXml, "ResponseCode")){\r
+                                               \r
+                                               // note: ResponseCode appears within "response", not "decodedXml"\r
+                                       }else if(taskProcessor.utils.nodeExists(response, "ResponseCode")){\r
                                                taskProcessor.utils.log("DEBUG","ResponseCode node Exist ", isDebugLogEnabled)\r
-                                               String code = taskProcessor.utils.getNodeText1(decodedXml, "ResponseCode")\r
+                                               String code = taskProcessor.utils.getNodeText1(response, "ResponseCode")\r
                                                if(code.isEmpty() || code.equals("")){\r
                                                        // if ResponseCode blank then Success\r
                                                        taskProcessor.utils.log("DEBUG","ResponseCode node is empty", isDebugLogEnabled)\r
                                                        requestDataResponseCode = 0\r
                                                }else{\r
-                                                       requestDataResponseCode  = code.toInteger()\r
+                                                       requestDataResponseCode  = code as Integer\r
                                                        taskProcessor.utils.log("DEBUG","ResponseCode is: " + requestDataResponseCode, isDebugLogEnabled)\r
                                                }\r
                                        }else{\r
diff --git a/bpmn/MSOCommonBPMN/src/test/groovy/org/openecomp/mso/bpmn/common/scripts/SDNCAdapterUtilsTest.groovy b/bpmn/MSOCommonBPMN/src/test/groovy/org/openecomp/mso/bpmn/common/scripts/SDNCAdapterUtilsTest.groovy
new file mode 100644 (file)
index 0000000..2b63100
--- /dev/null
@@ -0,0 +1,180 @@
+/*- \r
+ * ============LICENSE_START======================================================= \r
+ * ONAP - SO \r
+ * ================================================================================ \r
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. \r
+ * ================================================================================ \r
+ * Licensed under the Apache License, Version 2.0 (the "License"); \r
+ * you may not use this file except in compliance with the License. \r
+ * You may obtain a copy of the License at \r
+ * \r
+ *      http://www.apache.org/licenses/LICENSE-2.0 \r
+ * \r
+ * Unless required by applicable law or agreed to in writing, software \r
+ * distributed under the License is distributed on an "AS IS" BASIS, \r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. \r
+ * See the License for the specific language governing permissions and \r
+ * limitations under the License. \r
+ * ============LICENSE_END========================================================= \r
+ */ \r
+\r
+package org.openecomp.mso.bpmn.common.scripts;\r
+\r
+import static org.junit.Assert.*;\r
+import static org.mockito.Mockito.*\r
+\r
+import org.junit.Before\r
+import org.junit.Test\r
+import org.camunda.bpm.engine.delegate.BpmnError\r
+import org.camunda.bpm.engine.impl.persistence.entity.ExecutionEntity\r
+import org.camunda.bpm.engine.runtime.Execution\r
+import org.openecomp.mso.bpmn.core.WorkflowException\r
+import org.openecomp.mso.bpmn.common.scripts.SDNCAdapterUtils\r
+\r
+import org.openecomp.mso.bpmn.mock.FileUtil\r
+\r
+public class SDNCAdapterUtilsTest {\r
+       \r
+       private def map\r
+       private ExecutionEntity svcex\r
+       private WorkflowException wfex\r
+       private AbstractServiceTaskProcessor tp\r
+       private String resp\r
+       private SDNCAdapterUtils utils\r
+       \r
+       @Before\r
+       public void init()\r
+       {\r
+               map = new HashMap<String,Object>()\r
+               svcex = mock(ExecutionEntity.class)\r
+               wfex = null\r
+               tp = new AbstractServiceTaskProcessor() {\r
+                       @Override\r
+                       public void preProcessRequest(Execution execution) {\r
+                       }\r
+               };\r
+               utils = new SDNCAdapterUtils(tp)\r
+               \r
+               // svcex gets its variables from "map"\r
+               when(svcex.getVariable(any())).thenAnswer(\r
+                       { invocation ->\r
+                               return map.get(invocation.getArgumentAt(0, String.class)) })\r
+               \r
+               // svcex puts its variables into "map"\r
+               when(svcex.setVariable(any(), any())).thenAnswer(\r
+                       { invocation ->\r
+                               return map.put(\r
+                                                       invocation.getArgumentAt(0, String.class),\r
+                                                       invocation.getArgumentAt(1, String.class)) })\r
+               \r
+               map.put("isDebugLogEnabled", "true")\r
+               map.put("prefix", "mypfx-")\r
+               map.put("testProcessKey", "mykey")\r
+       }\r
+                                                                                               \r
+       @Test\r
+       public void testValidateSDNCResponse_Success_NoCode() {\r
+               resp = """<no-response/>"""\r
+               \r
+               utils.validateSDNCResponse(svcex, resp, wfex, true)\r
+               \r
+               assertEquals(true, map.get("mypfx-sdncResponseSuccess"))\r
+               assertEquals("0", map.get("mypfx-sdncRequestDataResponseCode"))\r
+               assertFalse(map.containsKey("WorkflowException"))\r
+       }\r
+                                                                                               \r
+       @Test\r
+       public void testValidateSDNCResponse_200() {\r
+               utils.validateSDNCResponse(svcex, makeResp("200", "OK", ""), wfex, true)\r
+               \r
+               assertEquals(true, map.get("mypfx-sdncResponseSuccess"))\r
+               assertEquals("200", map.get("mypfx-sdncRequestDataResponseCode"))\r
+               assertFalse(map.containsKey("WorkflowException"))\r
+       }\r
+                                                                                               \r
+       @Test\r
+       public void testValidateSDNCResponse_408() {\r
+               try {\r
+                       utils.validateSDNCResponse(svcex, makeResp("408", "failed", ""), wfex, true)\r
+                       \r
+                       // this has been commented out as, currently, the code doesn't\r
+                       // throw an exception in this case\r
+//                     fail("missing exception")\r
+                       \r
+               } catch(BpmnError ex) {\r
+                       ex.printStackTrace()\r
+               }\r
+               \r
+               assertEquals(false, map.get("mypfx-sdncResponseSuccess"))\r
+               assertEquals("408", map.get("mypfx-sdncRequestDataResponseCode"))\r
+               \r
+               wfex = map.get("WorkflowException")\r
+               assertNotNull(wfex)\r
+               \r
+               assertEquals(5320, wfex.getErrorCode())\r
+               assertEquals("Received error from SDN-C: failed", wfex.getErrorMessage())\r
+       }\r
+                                                                                               \r
+       @Test\r
+       public void testValidateSDNCResponse_408_200() {\r
+               \r
+               utils.validateSDNCResponse(svcex, makeResp("408", "failed", makeReq("200", "ok")), wfex, true)\r
+               \r
+               assertEquals(true, map.get("mypfx-sdncResponseSuccess"))\r
+               assertEquals("200", map.get("mypfx-sdncRequestDataResponseCode"))               \r
+               assertFalse(map.containsKey("WorkflowException"))\r
+       }\r
+                                                                                               \r
+       @Test\r
+       public void testValidateSDNCResponse_408_200_WithEmbeddedLt() {\r
+               \r
+               utils.validateSDNCResponse(svcex, makeResp("408", "failed", makeReq("200", "<success> message")), wfex, true)\r
+               \r
+               assertEquals(true, map.get("mypfx-sdncResponseSuccess"))\r
+               assertEquals("200", map.get("mypfx-sdncRequestDataResponseCode"))               \r
+               assertFalse(map.containsKey("WorkflowException"))\r
+       }\r
+       \r
+       \r
+       private String makeResp(String respcode, String respmsg, String reqdata) {\r
+               def rc = encodeXml(respcode)\r
+               def rm = encodeXml(respmsg)\r
+               \r
+               return """\r
+<sdncadapterworkflow:SDNCAdapterWorkflowResponse xmlns:sdncadapterworkflow="http://org.openecomp/mso/workflow/schema/v1"\r
+                                                 xmlns:tag0="http://org.openecomp/workflow/sdnc/adapter/schema/v1"\r
+                                                 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">\r
+   <sdncadapterworkflow:response-data>\r
+      <tag0:CallbackHeader>\r
+         <tag0:RequestId>myreq</tag0:RequestId>\r
+         <tag0:ResponseCode>${rc}</tag0:ResponseCode>\r
+         <tag0:ResponseMessage>${rm}</tag0:ResponseMessage>\r
+      </tag0:CallbackHeader>\r
+         ${reqdata}\r
+   </sdncadapterworkflow:response-data>\r
+</sdncadapterworkflow:SDNCAdapterWorkflowResponse>\r
+"""\r
+       \r
+       }\r
+       \r
+       private String makeReq(String respcode, String respmsg) {\r
+               def rc = encodeXml(respcode)\r
+               def rm = encodeXml(respmsg)\r
+               \r
+               def output = """\r
+<output xmlns="org:onap:sdnc:northbound:generic-resource">\r
+               <svc-request-id>8b46e36e-b44f-4085-9404-427be1bc8a3</svc-request-id>\r
+               <response-code>${rc}</response-code>\r
+               <response-message>${rm}</response-message>\r
+               <ack-final-indicator>Y</ack-final-indicator>\r
+</output>\r
+"""\r
+               output = encodeXml(output)\r
+               \r
+               return """<tag0:RequestData xsi:type="xs:string">${output}</tag0:RequestData>"""\r
+       }\r
+       \r
+       private String encodeXml(String txt) {\r
+               return txt.replace("&", "&amp;").replace("<", "&lt;")\r
+       }\r
+}\r