From 7754fb8e889bae843d7382b7dee4b2e21a4ef56c Mon Sep 17 00:00:00 2001 From: Jim Hahn Date: Mon, 30 Oct 2017 15:58:19 -0400 Subject: Handle embedded "<" in SDNC responses Modified the code to use an actual XML parser when decoding the SDNC response-data element, instead of using the simple-minded replace("&", "&") 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 --- .../bpmn/common/scripts/SDNCAdapterUtils.groovy | 29 ++-- .../common/scripts/SDNCAdapterUtilsTest.groovy | 180 +++++++++++++++++++++ 2 files changed, 194 insertions(+), 15 deletions(-) create mode 100644 bpmn/MSOCommonBPMN/src/test/groovy/org/openecomp/mso/bpmn/common/scripts/SDNCAdapterUtilsTest.groovy diff --git a/bpmn/MSOCommonBPMN/src/main/groovy/org/openecomp/mso/bpmn/common/scripts/SDNCAdapterUtils.groovy b/bpmn/MSOCommonBPMN/src/main/groovy/org/openecomp/mso/bpmn/common/scripts/SDNCAdapterUtils.groovy index b35616680b..c43f88434d 100644 --- a/bpmn/MSOCommonBPMN/src/main/groovy/org/openecomp/mso/bpmn/common/scripts/SDNCAdapterUtils.groovy +++ b/bpmn/MSOCommonBPMN/src/main/groovy/org/openecomp/mso/bpmn/common/scripts/SDNCAdapterUtils.groovy @@ -24,7 +24,7 @@ import org.apache.commons.lang3.* import org.camunda.bpm.engine.delegate.BpmnError import org.camunda.bpm.engine.runtime.Execution import org.openecomp.mso.bpmn.core.WorkflowException -import org.openecomp.mso.bpmn.core.json.JsonUtils; +import org.openecomp.mso.bpmn.core.json.JsonUtils import org.springframework.web.util.UriUtils @@ -730,13 +730,8 @@ class SDNCAdapterUtils { taskProcessor.utils.log("DEBUG", response + ' is empty'); exceptionUtil.buildAndThrowWorkflowException(execution, 500, "SDNCAdapter Workflow Response is Empty") }else{ - // we need to peer into the request data for error - def String sdncAdapterWorkflowResponse = taskProcessor.utils.getNodeXml(response, 'response-data', false) - def String decodedXml = decodeXML(sdncAdapterWorkflowResponse).replace('', "") - - // change '&' to "& (if present as data, ex: subscriber-name = 'FOUR SEASONS HEATING & COOLING_8310006378683' - decodedXml = decodedXml.replace("&", "&") + def String decodedXml = taskProcessor.utils.getNodeText1(response, "RequestData") taskProcessor.utils.log("DEBUG","decodedXml:\n" + decodedXml, isDebugLogEnabled) @@ -745,12 +740,14 @@ class SDNCAdapterUtils { try{ if (taskProcessor.utils.nodeExists(decodedXml, "response-message")) { - requestDataResponseMessage = taskProcessor.utils.getNodeText(decodedXml, "response-message") - } else if (taskProcessor.utils.nodeExists(decodedXml, "ResponseMessage")) { - requestDataResponseMessage = taskProcessor.utils.getNodeText(decodedXml, "ResponseMessage") + requestDataResponseMessage = taskProcessor.utils.getNodeText1(decodedXml, "response-message") + + // note: ResponseMessage appears within "response", not "decodedXml" + } else if (taskProcessor.utils.nodeExists(response, "ResponseMessage")) { + requestDataResponseMessage = taskProcessor.utils.getNodeText1(response, "ResponseMessage") } }catch(Exception e){ - taskProcessor.utils.log("DEBUG", 'Error caught while decoding resposne ' + e.getMessage(), isDebugLogEnabled) + taskProcessor.utils.log("DEBUG", 'Error caught while decoding response ' + e.getMessage(), isDebugLogEnabled) } if(taskProcessor.utils.nodeExists(decodedXml, "response-code")) { @@ -761,18 +758,20 @@ class SDNCAdapterUtils { taskProcessor.utils.log("DEBUG","response-code node is empty", isDebugLogEnabled) requestDataResponseCode = 0 }else{ - requestDataResponseCode = code.toInteger() + requestDataResponseCode = code as Integer taskProcessor.utils.log("DEBUG","response-code is: " + requestDataResponseCode, isDebugLogEnabled) } - }else if(taskProcessor.utils.nodeExists(decodedXml, "ResponseCode")){ + + // note: ResponseCode appears within "response", not "decodedXml" + }else if(taskProcessor.utils.nodeExists(response, "ResponseCode")){ taskProcessor.utils.log("DEBUG","ResponseCode node Exist ", isDebugLogEnabled) - String code = taskProcessor.utils.getNodeText1(decodedXml, "ResponseCode") + String code = taskProcessor.utils.getNodeText1(response, "ResponseCode") if(code.isEmpty() || code.equals("")){ // if ResponseCode blank then Success taskProcessor.utils.log("DEBUG","ResponseCode node is empty", isDebugLogEnabled) requestDataResponseCode = 0 }else{ - requestDataResponseCode = code.toInteger() + requestDataResponseCode = code as Integer taskProcessor.utils.log("DEBUG","ResponseCode is: " + requestDataResponseCode, isDebugLogEnabled) } }else{ 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 index 0000000000..2b63100510 --- /dev/null +++ b/bpmn/MSOCommonBPMN/src/test/groovy/org/openecomp/mso/bpmn/common/scripts/SDNCAdapterUtilsTest.groovy @@ -0,0 +1,180 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP - 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.openecomp.mso.bpmn.common.scripts; + +import static org.junit.Assert.*; +import static org.mockito.Mockito.* + +import org.junit.Before +import org.junit.Test +import org.camunda.bpm.engine.delegate.BpmnError +import org.camunda.bpm.engine.impl.persistence.entity.ExecutionEntity +import org.camunda.bpm.engine.runtime.Execution +import org.openecomp.mso.bpmn.core.WorkflowException +import org.openecomp.mso.bpmn.common.scripts.SDNCAdapterUtils + +import org.openecomp.mso.bpmn.mock.FileUtil + +public class SDNCAdapterUtilsTest { + + private def map + private ExecutionEntity svcex + private WorkflowException wfex + private AbstractServiceTaskProcessor tp + private String resp + private SDNCAdapterUtils utils + + @Before + public void init() + { + map = new HashMap() + svcex = mock(ExecutionEntity.class) + wfex = null + tp = new AbstractServiceTaskProcessor() { + @Override + public void preProcessRequest(Execution execution) { + } + }; + utils = new SDNCAdapterUtils(tp) + + // svcex gets its variables from "map" + when(svcex.getVariable(any())).thenAnswer( + { invocation -> + return map.get(invocation.getArgumentAt(0, String.class)) }) + + // svcex puts its variables into "map" + when(svcex.setVariable(any(), any())).thenAnswer( + { invocation -> + return map.put( + invocation.getArgumentAt(0, String.class), + invocation.getArgumentAt(1, String.class)) }) + + map.put("isDebugLogEnabled", "true") + map.put("prefix", "mypfx-") + map.put("testProcessKey", "mykey") + } + + @Test + public void testValidateSDNCResponse_Success_NoCode() { + resp = """""" + + utils.validateSDNCResponse(svcex, resp, wfex, true) + + assertEquals(true, map.get("mypfx-sdncResponseSuccess")) + assertEquals("0", map.get("mypfx-sdncRequestDataResponseCode")) + assertFalse(map.containsKey("WorkflowException")) + } + + @Test + public void testValidateSDNCResponse_200() { + utils.validateSDNCResponse(svcex, makeResp("200", "OK", ""), wfex, true) + + assertEquals(true, map.get("mypfx-sdncResponseSuccess")) + assertEquals("200", map.get("mypfx-sdncRequestDataResponseCode")) + assertFalse(map.containsKey("WorkflowException")) + } + + @Test + public void testValidateSDNCResponse_408() { + try { + utils.validateSDNCResponse(svcex, makeResp("408", "failed", ""), wfex, true) + + // this has been commented out as, currently, the code doesn't + // throw an exception in this case +// fail("missing exception") + + } catch(BpmnError ex) { + ex.printStackTrace() + } + + assertEquals(false, map.get("mypfx-sdncResponseSuccess")) + assertEquals("408", map.get("mypfx-sdncRequestDataResponseCode")) + + wfex = map.get("WorkflowException") + assertNotNull(wfex) + + assertEquals(5320, wfex.getErrorCode()) + assertEquals("Received error from SDN-C: failed", wfex.getErrorMessage()) + } + + @Test + public void testValidateSDNCResponse_408_200() { + + utils.validateSDNCResponse(svcex, makeResp("408", "failed", makeReq("200", "ok")), wfex, true) + + assertEquals(true, map.get("mypfx-sdncResponseSuccess")) + assertEquals("200", map.get("mypfx-sdncRequestDataResponseCode")) + assertFalse(map.containsKey("WorkflowException")) + } + + @Test + public void testValidateSDNCResponse_408_200_WithEmbeddedLt() { + + utils.validateSDNCResponse(svcex, makeResp("408", "failed", makeReq("200", " message")), wfex, true) + + assertEquals(true, map.get("mypfx-sdncResponseSuccess")) + assertEquals("200", map.get("mypfx-sdncRequestDataResponseCode")) + assertFalse(map.containsKey("WorkflowException")) + } + + + private String makeResp(String respcode, String respmsg, String reqdata) { + def rc = encodeXml(respcode) + def rm = encodeXml(respmsg) + + return """ + + + + myreq + ${rc} + ${rm} + + ${reqdata} + + +""" + + } + + private String makeReq(String respcode, String respmsg) { + def rc = encodeXml(respcode) + def rm = encodeXml(respmsg) + + def output = """ + + 8b46e36e-b44f-4085-9404-427be1bc8a3 + ${rc} + ${rm} + Y + +""" + output = encodeXml(output) + + return """${output}""" + } + + private String encodeXml(String txt) { + return txt.replace("&", "&").replace("<", "<") + } +} -- cgit 1.2.3-korg