/*- * ============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; import static org.junit.Assert.assertEquals; import static org.junit.Assert.fail; import java.io.IOException; import java.io.StringReader; import java.lang.management.ManagementFactory; import java.lang.management.RuntimeMXBean; import java.lang.reflect.Field; import java.lang.reflect.Modifier; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.UUID; import javax.ws.rs.core.Response; import javax.xml.bind.JAXBException; import javax.xml.namespace.NamespaceContext; import javax.xml.namespace.QName; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; import javax.xml.xpath.XPath; import javax.xml.xpath.XPathConstants; import javax.xml.xpath.XPathExpression; import javax.xml.xpath.XPathExpressionException; import javax.xml.xpath.XPathFactory; import org.camunda.bpm.engine.RuntimeService; import org.camunda.bpm.engine.history.HistoricProcessInstance; import org.camunda.bpm.engine.history.HistoricVariableInstance; import org.camunda.bpm.engine.runtime.ProcessInstance; import org.camunda.bpm.engine.test.ProcessEngineRule; import org.camunda.bpm.engine.variable.impl.VariableMapImpl; import org.custommonkey.xmlunit.DetailedDiff; import org.custommonkey.xmlunit.XMLUnit; import org.jboss.resteasy.spi.AsynchronousResponse; import org.json.JSONArray; import org.junit.Before; import org.junit.Rule; import org.openecomp.mso.bpmn.common.adapter.sdnc.CallbackHeader; import org.openecomp.mso.bpmn.common.adapter.sdnc.SDNCAdapterCallbackRequest; import org.openecomp.mso.bpmn.common.adapter.sdnc.SDNCAdapterResponse; import org.openecomp.mso.bpmn.common.adapter.vnf.CreateVnfNotification; import org.openecomp.mso.bpmn.common.adapter.vnf.DeleteVnfNotification; import org.openecomp.mso.bpmn.common.adapter.vnf.MsoExceptionCategory; import org.openecomp.mso.bpmn.common.adapter.vnf.MsoRequest; import org.openecomp.mso.bpmn.common.adapter.vnf.UpdateVnfNotification; import org.openecomp.mso.bpmn.common.adapter.vnf.VnfRollback; import org.openecomp.mso.bpmn.common.workflow.service.SDNCAdapterCallbackServiceImpl; import org.openecomp.mso.bpmn.common.workflow.service.VnfAdapterNotifyServiceImpl; import org.openecomp.mso.bpmn.common.workflow.service.WorkflowAsyncResource; import org.openecomp.mso.bpmn.common.workflow.service.WorkflowMessageResource; import org.openecomp.mso.bpmn.common.workflow.service.WorkflowResponse; import org.openecomp.mso.bpmn.core.utils.CamundaDBSetup; import org.openecomp.mso.bpmn.core.PropertyConfigurationSetup; import org.openecomp.mso.bpmn.core.domain.Resource; import org.openecomp.mso.bpmn.core.domain.ServiceDecomposition; import static org.openecomp.mso.bpmn.core.json.JsonUtils.*; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.Node; import org.w3c.dom.NodeList; import org.xml.sax.InputSource; import org.xml.sax.SAXException; import com.github.tomakehurst.wiremock.core.WireMockConfiguration; import com.github.tomakehurst.wiremock.extension.ResponseTransformer; import com.github.tomakehurst.wiremock.junit.WireMockRule; /** * A base class for Workflow tests. *
* WireMock response transformers may be specified by declaring public * static fields with the @WorkflowTestTransformer annotation. For example: *
* @WorkflowTestTransformer * public static final ResponseTransformer sdncAdapterMockTransformer = * new SDNCAdapterMockTransformer(); **/ public class WorkflowTest { @Rule public final ProcessEngineRule processEngineRule = new ProcessEngineRule(); @Rule public final WireMockRule wireMockRule; /** * Content-Type for XML. */ protected static final String XML = "application/xml"; /** * Content-Type for JSON. */ protected static final String JSON = "application/json; charset=UTF-8"; /** * Constructor. */ public WorkflowTest() throws RuntimeException { // Process WorkflowTestTransformer annotations List
* reserve, assign, delete:ERR ** Errors are handled with junit assertions and will cause the test to fail. * @param callbacks an object containing callback data for the program * @param program the program to execute */ protected void injectSDNCRestCallbacks(CallbackSet callbacks, String program) { String[] cmds = program.replaceAll("\\s+", "").split(","); for (String cmd : cmds) { String action = cmd; String modifier = "STD"; if (cmd.contains(":")) { String[] parts = cmd.split(":"); action = parts[0]; modifier = parts[1]; } String content = null; String contentType = null; if ("STD".equals(modifier)) { CallbackData callbackData = callbacks.get(action); if (callbackData == null) { String msg = "No callback defined for '" + action + "' SDNC request"; System.out.println(msg); fail(msg); } content = callbackData.getContent(); contentType = callbackData.getContentType(); } else if ("ERR".equals(modifier)) { content = "{\"SDNCServiceError\":{\"sdncRequestId\":\"((REQUEST-ID))\",\"responseCode\":\"500\",\"responseMessage\":\"SIMULATED ERROR FROM SDNC ADAPTER\",\"ackFinalIndicator\":\"Y\"}}"; contentType = JSON; } else { String msg = "Invalid SDNC program modifier: '" + modifier + "'"; System.out.println(msg); fail(msg); } if (contentType == null) { // Default for backward compatibility with existing tests. contentType = JSON; } if (!injectSDNCRestCallback(contentType, content, 10000)) { fail("Failed to inject SDNC '" + action + "' callback"); } try { Thread.sleep(1000); } catch (InterruptedException e) { fail("Interrupted after injection of SDNC '" + action + "' callback"); } } } /** * Runs a program to inject SDNC events into the test environment. * A program is essentially just a list of keys that identify event data * to be injected, in sequence. An example program: *
* event1, event2 ** NOTE: Each callback must have a message type associated with it, e.g. * "SDNCAEvent". * Errors are handled with junit assertions and will cause the test to fail. * @param callbacks an object containing event data for the program * @param program the program to execute */ protected void injectSDNCEvents(CallbackSet callbacks, String program) { injectWorkflowMessages(callbacks, program); } /** * Runs a program to inject SDNC callback data into the test environment. * A program is essentially just a list of keys that identify callback data * to be injected, in sequence. An example program: *
* reserve, assign, delete:ERR ** Errors are handled with junit assertions and will cause the test to fail. * @param callbacks an object containing callback data for the program * @param program the program to execute */ protected void injectSDNCCallbacks(CallbackSet callbacks, String program) { String[] cmds = program.replaceAll("\\s+", "").split(","); for (String cmd : cmds) { String action = cmd; String modifier = "STD"; if (cmd.contains(":")) { String[] parts = cmd.split(":"); action = parts[0]; modifier = parts[1]; } String content = null; int respCode = 200; String respMsg = "OK"; if ("STD".equals(modifier)) { CallbackData callbackData = callbacks.get(action); if (callbackData == null) { String msg = "No callback defined for '" + action + "' SDNC request"; System.out.println(msg); fail(msg); } content = callbackData.getContent(); respCode = 200; respMsg = "OK"; } else if ("CREATED".equals(modifier)) { CallbackData callbackData = callbacks.get(action); if (callbackData == null) { String msg = "No callback defined for '" + action + "' SDNC request"; System.out.println(msg); fail(msg); } content = callbackData.getContent(); respCode = 201; respMsg = "Created"; } else if ("ERR".equals(modifier)) { content = "
* create, rollback ** Errors are handled with junit assertions and will cause the test to fail. * @param callbacks an object containing callback data for the program * @param program the program to execute */ protected void injectVNFRestCallbacks(CallbackSet callbacks, String program) { String[] cmds = program.replaceAll("\\s+", "").split(","); for (String cmd : cmds) { String action = cmd; String modifier = "STD"; if (cmd.contains(":")) { String[] parts = cmd.split(":"); action = parts[0]; modifier = parts[1]; } String content = null; String contentType = null; if ("STD".equals(modifier)) { CallbackData callbackData = callbacks.get(action); if (callbackData == null) { String msg = "No callback defined for '" + action + "' VNF REST request"; System.out.println(msg); fail(msg); } content = callbackData.getContent(); contentType = callbackData.getContentType(); } else if ("ERR".equals(modifier)) { content = "SIMULATED ERROR FROM VNF ADAPTER"; contentType = "text/plain"; } else { String msg = "Invalid VNF REST program modifier: '" + modifier + "'"; System.out.println(msg); fail(msg); } if (contentType == null) { // Default for backward compatibility with existing tests. contentType = XML; } if (!injectVnfAdapterRestCallback(contentType, content, 10000)) { fail("Failed to inject VNF REST '" + action + "' callback"); } try { Thread.sleep(1000); } catch (InterruptedException e) { fail("Interrupted after injection of VNF REST '" + action + "' callback"); } } } /** * Runs a program to inject VNF callback data into the test environment. * A program is essentially just a list of keys that identify callback data * to be injected, in sequence. An example program: *
* createVnf, deleteVnf ** Errors are handled with junit assertions and will cause the test to fail. * @param callbacks an object containing callback data for the program * @param program the program to execute */ protected void injectVNFCallbacks(CallbackSet callbacks, String program) { String[] cmds = program.replaceAll("\\s+", "").split(","); for (String cmd : cmds) { String action = cmd; String modifier = "STD"; if (cmd.contains(":")) { String[] parts = cmd.split(":"); action = parts[0]; modifier = parts[1]; } String content = null; if ("STD".equals(modifier)) { CallbackData callbackData = callbacks.get(action); if (callbackData == null) { String msg = "No callback defined for '" + action + "' VNF request"; System.out.println(msg); fail(msg); } content = callbackData.getContent(); } else if ("ERR".equals(modifier)) { String msg = "Currently unsupported VNF program modifier: '" + modifier + "'"; System.out.println(msg); fail(msg); } else { String msg = "Invalid VNF program modifier: '" + modifier + "'"; System.out.println(msg); fail(msg); } boolean injected = false; if (content.contains("createVnfNotification")) { injected = injectCreateVNFCallback(content, 10000); } else if (content.contains("deleteVnfNotification")) { injected = injectDeleteVNFCallback(content, 10000); } else if (content.contains("updateVnfNotification")) { injected = injectUpdateVNFCallback(content, 10000); } if (!injected) { String msg = "Failed to inject VNF '" + action + "' callback"; System.out.println(msg); fail(msg); } try { Thread.sleep(1000); } catch (InterruptedException e) { fail("Interrupted after injection of VNF '" + action + "' callback"); } } } /** * Waits for the number of running processes with the specified process * definition key to equal a particular count. * @param processKey the process definition key * @param count the desired count * @param timeout the timeout in milliseconds */ protected void waitForRunningProcessCount(String processKey, int count, long timeout) { System.out.println("Waiting " + timeout + "ms for there to be " + count + " " + processKey + " instances"); long now = System.currentTimeMillis() + timeout; long endTime = now + timeout; int last = -1; while (now <= endTime) { int actual = processEngineRule.getRuntimeService() .createProcessInstanceQuery() .processDefinitionKey(processKey) .list().size(); if (actual != last) { System.out.println("There are now " + actual + " " + processKey + " instances"); last = actual; } if (actual == count) { return; } try { Thread.sleep(200); } catch (InterruptedException e) { String msg = "Interrupted waiting for there to be " + count + " " + processKey + " instances"; System.out.println(msg); fail(msg); } now = System.currentTimeMillis(); } String msg = "Timed out waiting for there to be " + count + " " + processKey + " instances"; System.out.println(msg); fail(msg); } /** * Waits for the specified process variable to be set. * @param processKey the process definition key * @param variable the variable name * @param timeout the timeout in milliseconds * @return the variable value, or null if it cannot be obtained * in the specified time */ protected Object getProcessVariable(String processKey, String variable, long timeout) { System.out.println("Waiting " + timeout + "ms for " + processKey + "." + variable + " to be set"); long now = System.currentTimeMillis() + timeout; long endTime = now + timeout; ProcessInstance processInstance = null; Object value = null; while (value == null) { if (now > endTime) { if (processInstance == null) { System.out.println("Timed out waiting for " + processKey + " to start"); } else { System.out.println("Timed out waiting for " + processKey + "[" + processInstance.getId() + "]." + variable + " to be set"); } return null; } if (processInstance == null) { processInstance = processEngineRule.getRuntimeService() .createProcessInstanceQuery() .processDefinitionKey(processKey) .singleResult(); } if (processInstance != null) { value = processEngineRule.getRuntimeService() .getVariable(processInstance.getId(), variable); } try { Thread.sleep(200); } catch (InterruptedException e) { System.out.println("Interrupted waiting for " + processKey + "." + variable + " to be set"); return null; } now = System.currentTimeMillis(); } System.out.println(processKey + "[" + processInstance.getId() + "]." + variable + "=" + value); return value; } /** * Injects a single SDNC adapter callback request. The specified callback data * may contain the placeholder string ((REQUEST-ID)) which is replaced with * the actual SDNC request ID. Note: this is not the requestId in the original * MSO request. * @param contentType the HTTP content type for the callback * @param content the content of the callback * @param timeout the timeout in milliseconds * @return true if the callback could be injected, false otherwise */ protected boolean injectSDNCRestCallback(String contentType, String content, long timeout) { String sdncRequestId = (String) getProcessVariable("SDNCAdapterRestV1", "SDNCAResponse_CORRELATOR", timeout); if (sdncRequestId == null) { return false; } content = content.replace("((REQUEST-ID))", sdncRequestId); // Deprecated usage. All test code should switch to the (( ... )) syntax. content = content.replace("{{REQUEST-ID}}", sdncRequestId); System.out.println("Injecting SDNC adapter callback"); WorkflowMessageResource workflowMessageResource = new WorkflowMessageResource(); workflowMessageResource.setProcessEngineServices4junit(processEngineRule); Response response = workflowMessageResource.deliver(contentType, "SDNCAResponse", sdncRequestId, content); System.out.println("Workflow response to SDNC adapter callback: " + response); return true; } /** * Injects a single SDNC adapter callback request. The specified callback data * may contain the placeholder string ((REQUEST-ID)) which is replaced with * the actual SDNC request ID. Note: this is not the requestId in the original * MSO request. * @param content the content of the callback * @param respCode the response code (normally 200) * @param respMsg the response message (normally "OK") * @param timeout the timeout in milliseconds * @return true if the callback could be injected, false otherwise */ protected boolean injectSDNCCallback(int respCode, String respMsg, String content, long timeout) { String sdncRequestId = (String) getProcessVariable("sdncAdapter", "SDNCA_requestId", timeout); if (sdncRequestId == null) { return false; } content = content.replace("((REQUEST-ID))", sdncRequestId); // Deprecated usage. All test code should switch to the (( ... )) syntax. content = content.replace("{{REQUEST-ID}}", sdncRequestId); System.out.println("Injecting SDNC adapter callback"); CallbackHeader callbackHeader = new CallbackHeader(); callbackHeader.setRequestId(sdncRequestId); callbackHeader.setResponseCode(String.valueOf(respCode)); callbackHeader.setResponseMessage(respMsg); SDNCAdapterCallbackRequest sdncAdapterCallbackRequest = new SDNCAdapterCallbackRequest(); sdncAdapterCallbackRequest.setCallbackHeader(callbackHeader); sdncAdapterCallbackRequest.setRequestData(content); SDNCAdapterCallbackServiceImpl callbackService = new SDNCAdapterCallbackServiceImpl(); callbackService.setProcessEngineServices4junit(processEngineRule); SDNCAdapterResponse sdncAdapterResponse = callbackService.sdncAdapterCallback(sdncAdapterCallbackRequest); System.out.println("Workflow response to SDNC adapter callback: " + sdncAdapterResponse); return true; } /** * Injects a single VNF adapter callback request. The specified callback data * may contain the placeholder string ((MESSAGE-ID)) which is replaced with * the actual message ID. Note: this is not the requestId in the original * MSO request. * @param contentType the HTTP content type for the callback * @param content the content of the callback * @param timeout the timeout in milliseconds * @return true if the callback could be injected, false otherwise */ protected boolean injectVnfAdapterRestCallback(String contentType, String content, long timeout) { String messageId = (String) getProcessVariable("vnfAdapterRestV1", "VNFAResponse_CORRELATOR", timeout); if (messageId == null) { return false; } content = content.replace("((MESSAGE-ID))", messageId); // Deprecated usage. All test code should switch to the (( ... )) syntax. content = content.replace("{{MESSAGE-ID}}", messageId); System.out.println("Injecting VNF adapter callback"); WorkflowMessageResource workflowMessageResource = new WorkflowMessageResource(); workflowMessageResource.setProcessEngineServices4junit(processEngineRule); Response response = workflowMessageResource.deliver(contentType, "VNFAResponse", messageId, content); System.out.println("Workflow response to VNF adapter callback: " + response); return true; } /** * Injects a Create VNF adapter callback request. The specified callback data * may contain the placeholder string ((MESSAGE-ID)) which is replaced with * the actual message ID. It may also contain the placeholder string * ((REQUEST-ID)) which is replaced request ID of the original MSO request. * @param content the content of the callback * @param timeout the timeout in milliseconds * @return true if the callback could be injected, false otherwise * @throws JAXBException if the content does not adhere to the schema */ protected boolean injectCreateVNFCallback(String content, long timeout) { String messageId = (String) getProcessVariable("vnfAdapterCreateV1", "VNFC_messageId", timeout); if (messageId == null) { return false; } content = content.replace("((MESSAGE-ID))", messageId); // Deprecated usage. All test code should switch to the (( ... )) syntax. content = content.replace("{{MESSAGE-ID}}", messageId); if(content.contains("((REQUEST-ID))")){ content = content.replace("((REQUEST-ID))", msoRequestId); // Deprecated usage. All test code should switch to the (( ... )) syntax. content = content.replace("{{REQUEST-ID}}", msoRequestId); } System.out.println("Injecting VNF adapter callback"); // Is it possible to unmarshal this with JAXB? I couldn't. CreateVnfNotification createVnfNotification = new CreateVnfNotification(); XPathTool xpathTool = new VnfNotifyXPathTool(); xpathTool.setXML(content); try { String completed = xpathTool.evaluate( "/tns:createVnfNotification/tns:completed/text()"); createVnfNotification.setCompleted("true".equals(completed)); String vnfId = xpathTool.evaluate( "/tns:createVnfNotification/tns:vnfId/text()"); createVnfNotification.setVnfId(vnfId); NodeList entries = (NodeList) xpathTool.evaluate( "/tns:createVnfNotification/tns:outputs/tns:entry", XPathConstants.NODESET); CreateVnfNotificationOutputs outputs = new CreateVnfNotificationOutputs(); for (int i = 0; i < entries.getLength(); i++) { Node node = entries.item(i); if (node.getNodeType() == Node.ELEMENT_NODE) { Element entry = (Element) node; String key = entry.getElementsByTagNameNS("*", "key").item(0).getTextContent(); String value = entry.getElementsByTagNameNS("*", "value").item(0).getTextContent(); outputs.add(key, value); } } createVnfNotification.setOutputs(outputs); VnfRollback rollback = new VnfRollback(); String cloudSiteId = xpathTool.evaluate( "/tns:createVnfNotification/tns:rollback/tns:cloudSiteId/text()"); rollback.setCloudSiteId(cloudSiteId); String requestId = xpathTool.evaluate( "/tns:createVnfNotification/tns:rollback/tns:msoRequest/tns:requestId/text()"); String serviceInstanceId = xpathTool.evaluate( "/tns:createVnfNotification/tns:rollback/tns:msoRequest/tns:serviceInstanceId/text()"); if (requestId != null || serviceInstanceId != null) { MsoRequest msoRequest = new MsoRequest(); msoRequest.setRequestId(requestId); msoRequest.setServiceInstanceId(serviceInstanceId); rollback.setMsoRequest(msoRequest); } String tenantCreated = xpathTool.evaluate( "/tns:createVnfNotification/tns:rollback/tns:tenantCreated/text()"); rollback.setTenantCreated("true".equals(tenantCreated)); String tenantId = xpathTool.evaluate( "/tns:createVnfNotification/tns:rollback/tns:tenantId/text()"); rollback.setTenantId(tenantId); String vnfCreated = xpathTool.evaluate( "/tns:createVnfNotification/tns:rollback/tns:vnfCreated/text()"); rollback.setVnfCreated("true".equals(vnfCreated)); String rollbackVnfId = xpathTool.evaluate( "/tns:createVnfNotification/tns:rollback/tns:vnfId/text()"); rollback.setVnfId(rollbackVnfId); createVnfNotification.setRollback(rollback); } catch (Exception e) { System.out.println("Failed to unmarshal VNF callback content:"); System.out.println(content); return false; } VnfAdapterNotifyServiceImpl notifyService = new VnfAdapterNotifyServiceImpl(); notifyService.setProcessEngineServices4junit(processEngineRule); notifyService.createVnfNotification( messageId, createVnfNotification.isCompleted(), createVnfNotification.getException(), createVnfNotification.getErrorMessage(), createVnfNotification.getVnfId(), createVnfNotification.getOutputs(), createVnfNotification.getRollback()); return true; } /** * Injects a Delete VNF adapter callback request. The specified callback data * may contain the placeholder string ((MESSAGE-ID)) which is replaced with * the actual message ID. It may also contain the placeholder string * ((REQUEST-ID)) which is replaced request ID of the original MSO request. * @param content the content of the callback * @param timeout the timeout in milliseconds * @return true if the callback could be injected, false otherwise * @throws JAXBException if the content does not adhere to the schema */ protected boolean injectDeleteVNFCallback(String content, long timeout) { String messageId = (String) getProcessVariable("vnfAdapterDeleteV1", "VNFDEL_uuid", timeout); if (messageId == null) { return false; } content = content.replace("((MESSAGE-ID))", messageId); // Deprecated usage. All test code should switch to the (( ... )) syntax. content = content.replace("{{MESSAGE-ID}}", messageId); System.out.println("Injecting VNF adapter delete callback"); // Is it possible to unmarshal this with JAXB? I couldn't. DeleteVnfNotification deleteVnfNotification = new DeleteVnfNotification(); XPathTool xpathTool = new VnfNotifyXPathTool(); xpathTool.setXML(content); try { String completed = xpathTool.evaluate( "/tns:deleteVnfNotification/tns:completed/text()"); deleteVnfNotification.setCompleted("true".equals(completed)); // if notification failure, set the exception and error message if (deleteVnfNotification.isCompleted() == false) { deleteVnfNotification.setException(MsoExceptionCategory.INTERNAL); deleteVnfNotification.setErrorMessage(xpathTool.evaluate( "/tns:deleteVnfNotification/tns:errorMessage/text()")) ; } } catch (Exception e) { System.out.println("Failed to unmarshal VNF Delete callback content:"); System.out.println(content); return false; } VnfAdapterNotifyServiceImpl notifyService = new VnfAdapterNotifyServiceImpl(); notifyService.setProcessEngineServices4junit(processEngineRule); notifyService.deleteVnfNotification( messageId, deleteVnfNotification.isCompleted(), deleteVnfNotification.getException(), deleteVnfNotification.getErrorMessage()); return true; } /** * Injects a Update VNF adapter callback request. The specified callback data * may contain the placeholder string ((MESSAGE-ID)) which is replaced with * the actual message ID. It may also contain the placeholder string * ((REQUEST-ID)) which is replaced request ID of the original MSO request. * @param content the content of the callback * @param timeout the timeout in milliseconds * @return true if the callback could be injected, false otherwise * @throws JAXBException if the content does not adhere to the schema */ protected boolean injectUpdateVNFCallback(String content, long timeout) { String messageId = (String) getProcessVariable("vnfAdapterUpdate", "VNFU_messageId", timeout); if (messageId == null) { return false; } content = content.replace("((MESSAGE-ID))", messageId); // Deprecated usage. All test code should switch to the (( ... )) syntax. content = content.replace("{{MESSAGE-ID}}", messageId); content = content.replace("((REQUEST-ID))", msoRequestId); // Deprecated usage. All test code should switch to the (( ... )) syntax. content = content.replace("{{REQUEST-ID}}", msoRequestId); System.out.println("Injecting VNF adapter callback"); // Is it possible to unmarshal this with JAXB? I couldn't. UpdateVnfNotification updateVnfNotification = new UpdateVnfNotification(); XPathTool xpathTool = new VnfNotifyXPathTool(); xpathTool.setXML(content); try { String completed = xpathTool.evaluate( "/tns:updateVnfNotification/tns:completed/text()"); updateVnfNotification.setCompleted("true".equals(completed)); NodeList entries = (NodeList) xpathTool.evaluate( "/tns:updateVnfNotification/tns:outputs/tns:entry", XPathConstants.NODESET); UpdateVnfNotificationOutputs outputs = new UpdateVnfNotificationOutputs(); for (int i = 0; i < entries.getLength(); i++) { Node node = entries.item(i); if (node.getNodeType() == Node.ELEMENT_NODE) { Element entry = (Element) node; String key = entry.getElementsByTagNameNS("*", "key").item(0).getTextContent(); String value = entry.getElementsByTagNameNS("*", "value").item(0).getTextContent(); outputs.add(key, value); } } updateVnfNotification.setOutputs(outputs); VnfRollback rollback = new VnfRollback(); String cloudSiteId = xpathTool.evaluate( "/tns:updateVnfNotification/tns:rollback/tns:cloudSiteId/text()"); rollback.setCloudSiteId(cloudSiteId); String requestId = xpathTool.evaluate( "/tns:updateVnfNotification/tns:rollback/tns:msoRequest/tns:requestId/text()"); String serviceInstanceId = xpathTool.evaluate( "/tns:updateVnfNotification/tns:rollback/tns:msoRequest/tns:serviceInstanceId/text()"); if (requestId != null || serviceInstanceId != null) { MsoRequest msoRequest = new MsoRequest(); msoRequest.setRequestId(requestId); msoRequest.setServiceInstanceId(serviceInstanceId); rollback.setMsoRequest(msoRequest); } String tenantCreated = xpathTool.evaluate( "/tns:updateVnfNotification/tns:rollback/tns:tenantCreated/text()"); rollback.setTenantCreated("true".equals(tenantCreated)); String tenantId = xpathTool.evaluate( "/tns:updateVnfNotification/tns:rollback/tns:tenantId/text()"); rollback.setTenantId(tenantId); String vnfCreated = xpathTool.evaluate( "/tns:updateVnfNotification/tns:rollback/tns:vnfCreated/text()"); rollback.setVnfCreated("true".equals(vnfCreated)); String rollbackVnfId = xpathTool.evaluate( "/tns:updateVnfNotification/tns:rollback/tns:vnfId/text()"); rollback.setVnfId(rollbackVnfId); updateVnfNotification.setRollback(rollback); } catch (Exception e) { System.out.println("Failed to unmarshal VNF callback content:"); System.out.println(content); return false; } VnfAdapterNotifyServiceImpl notifyService = new VnfAdapterNotifyServiceImpl(); notifyService.setProcessEngineServices4junit(processEngineRule); notifyService.updateVnfNotification( messageId, updateVnfNotification.isCompleted(), updateVnfNotification.getException(), updateVnfNotification.getErrorMessage(), updateVnfNotification.getOutputs(), updateVnfNotification.getRollback()); return true; } /** * Runs a program to inject workflow messages into the test environment. * A program is essentially just a list of keys that identify event data * to be injected, in sequence. An example program: *
* event1, event2 ** Errors are handled with junit assertions and will cause the test to fail. * NOTE: Each callback must have a workflow message type associated with it. * @param callbacks an object containing event data for the program * @param program the program to execute */ protected void injectWorkflowMessages(CallbackSet callbacks, String program) { String[] cmds = program.replaceAll("\\s+", "").split(","); for (String cmd : cmds) { String action = cmd; String modifier = "STD"; if (cmd.contains(":")) { String[] parts = cmd.split(":"); action = parts[0]; modifier = parts[1]; } String messageType = null; String content = null; String contentType = null; if ("STD".equals(modifier)) { CallbackData callbackData = callbacks.get(action); if (callbackData == null) { String msg = "No '" + action + "' workflow message callback is defined"; System.out.println(msg); fail(msg); } messageType = callbackData.getMessageType(); if (messageType == null || messageType.trim().equals("")) { String msg = "No workflow message type is defined in the '" + action + "' callback"; System.out.println(msg); fail(msg); } content = callbackData.getContent(); contentType = callbackData.getContentType(); } else { String msg = "Invalid workflow message program modifier: '" + modifier + "'"; System.out.println(msg); fail(msg); } if (!injectWorkflowMessage(contentType, messageType, content, 10000)) { fail("Failed to inject '" + action + "' workflow message"); } try { Thread.sleep(1000); } catch (InterruptedException e) { fail("Interrupted after injection of '" + action + "' workflow message"); } } } /** * Injects a workflow message. The specified callback data may contain the * placeholder string ((CORRELATOR)) which is replaced with the actual * correlator value. * @param contentType the HTTP contentType for the message (possibly null) * @param messageType the message type * @param content the message content (possibly null) * @param timeout the timeout in milliseconds * @return true if the message could be injected, false otherwise */ protected boolean injectWorkflowMessage(String contentType, String messageType, String content, long timeout) { String correlator = (String) getProcessVariable("ReceiveWorkflowMessage", messageType + "_CORRELATOR", timeout); if (correlator == null) { return false; } if (content != null) { content = content.replace("((CORRELATOR))", correlator); } System.out.println("Injecting " + messageType + " message"); WorkflowMessageResource workflowMessageResource = new WorkflowMessageResource(); workflowMessageResource.setProcessEngineServices4junit(processEngineRule); Response response = workflowMessageResource.deliver(contentType, messageType, correlator, content); System.out.println("Workflow response to " + messageType + " message: " + response); return true; } /** * Runs a program to inject sniro workflow messages into the test environment. * A program is essentially just a list of keys that identify event data * to be injected, in sequence. For more details, see * injectSNIROCallbacks(String contentType, String messageType, String content, long timeout) * * Errors are handled with junit assertions and will cause the test to fail. * NOTE: Each callback must have a workflow message type associated with it. * * @param callbacks an object containing event data for the program * @param program the program to execute */ protected void injectSNIROCallbacks(CallbackSet callbacks, String program) { String[] cmds = program.replaceAll("\\s+", "").split(","); for (String cmd : cmds) { String action = cmd; String modifier = "STD"; if (cmd.contains(":")) { String[] parts = cmd.split(":"); action = parts[0]; modifier = parts[1]; } String messageType = null; String content = null; String contentType = null; if ("STD".equals(modifier)) { CallbackData callbackData = callbacks.get(action); if (callbackData == null) { String msg = "No '" + action + "' workflow message callback is defined"; System.out.println(msg); fail(msg); } messageType = callbackData.getMessageType(); if (messageType == null || messageType.trim().equals("")) { String msg = "No workflow message type is defined in the '" + action + "' callback"; System.out.println(msg); fail(msg); } content = callbackData.getContent(); contentType = callbackData.getContentType(); } else { String msg = "Invalid workflow message program modifier: '" + modifier + "'"; System.out.println(msg); fail(msg); } if (!injectSNIROCallbacks(contentType, messageType, content, 10000)) { fail("Failed to inject '" + action + "' workflow message"); } try { Thread.sleep(1000); } catch (InterruptedException e) { fail("Interrupted after injection of '" + action + "' workflow message"); } } } /** * Injects a sniro workflow message. The specified callback response may * contain the placeholder strings ((CORRELATOR)) and ((SERVICE_RESOURCE_ID)) * The ((CORRELATOR)) is replaced with the actual correlator value from the * request. The ((SERVICE_RESOURCE_ID)) is replaced with the actual serviceResourceId * value from the sniro request. Currently this only works with sniro request * that contain only 1 resource. * * @param contentType the HTTP contentType for the message (possibly null) * @param messageType the message type * @param content the message content (possibly null) * @param timeout the timeout in milliseconds * @return true if the message could be injected, false otherwise */ protected boolean injectSNIROCallbacks(String contentType, String messageType, String content, long timeout) { String correlator = (String) getProcessVariable("ReceiveWorkflowMessage", messageType + "_CORRELATOR", timeout); if (correlator == null) { return false; } if (content != null) { content = content.replace("((CORRELATOR))", correlator); if(messageType.equalsIgnoreCase("SNIROResponse")){ //TODO figure out a solution for when there is more than 1 resource being homed (i.e. more than 1 reason in the placement list) ServiceDecomposition decomp = (ServiceDecomposition) getProcessVariable("Homing", "serviceDecomposition", timeout); List