2 * ============LICENSE_START=======================================================
4 * ================================================================================
5 * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
6 * ================================================================================
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
11 * http://www.apache.org/licenses/LICENSE-2.0
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
18 * ============LICENSE_END=========================================================
21 package org.onap.so.bpmn.common;
23 import static org.junit.Assert.assertEquals;
24 import static org.junit.Assert.fail;
25 import static org.onap.so.bpmn.core.json.JsonUtils.getJsonValue;
26 import static org.onap.so.bpmn.core.json.JsonUtils.updJsonValue;
28 import java.io.IOException;
29 import java.io.StringReader;
30 import java.lang.management.ManagementFactory;
31 import java.lang.management.RuntimeMXBean;
32 import java.util.ArrayList;
33 import java.util.HashMap;
34 import java.util.Iterator;
35 import java.util.List;
37 import java.util.UUID;
39 import javax.ws.rs.core.Response;
40 import javax.xml.bind.JAXBException;
41 import javax.xml.namespace.NamespaceContext;
42 import javax.xml.namespace.QName;
43 import javax.xml.parsers.DocumentBuilder;
44 import javax.xml.parsers.DocumentBuilderFactory;
45 import javax.xml.parsers.ParserConfigurationException;
46 import javax.xml.xpath.XPath;
47 import javax.xml.xpath.XPathConstants;
48 import javax.xml.xpath.XPathExpression;
49 import javax.xml.xpath.XPathExpressionException;
50 import javax.xml.xpath.XPathFactory;
52 import org.camunda.bpm.engine.HistoryService;
53 import org.camunda.bpm.engine.ProcessEngine;
54 import org.camunda.bpm.engine.ProcessEngineException;
55 import org.camunda.bpm.engine.RuntimeService;
56 import org.camunda.bpm.engine.history.HistoricProcessInstance;
57 import org.camunda.bpm.engine.history.HistoricVariableInstance;
58 import org.camunda.bpm.engine.runtime.ProcessInstance;
59 import org.camunda.bpm.engine.test.ProcessEngineRule;
60 import org.camunda.bpm.engine.variable.impl.VariableMapImpl;
61 import org.custommonkey.xmlunit.DetailedDiff;
62 import org.custommonkey.xmlunit.XMLUnit;
63 import org.json.JSONArray;
64 import org.json.JSONObject;
65 import org.junit.Rule;
66 import org.onap.so.bpmn.common.adapter.sdnc.CallbackHeader;
67 import org.onap.so.bpmn.common.adapter.sdnc.SDNCAdapterCallbackRequest;
68 import org.onap.so.bpmn.common.adapter.sdnc.SDNCAdapterResponse;
69 import org.onap.so.bpmn.common.adapter.vnf.CreateVnfNotification;
70 import org.onap.so.bpmn.common.adapter.vnf.DeleteVnfNotification;
71 import org.onap.so.bpmn.common.adapter.vnf.MsoExceptionCategory;
72 import org.onap.so.bpmn.common.adapter.vnf.MsoRequest;
73 import org.onap.so.bpmn.common.adapter.vnf.UpdateVnfNotification;
74 import org.onap.so.bpmn.common.adapter.vnf.VnfRollback;
75 import org.onap.so.bpmn.common.workflow.context.WorkflowResponse;
76 import org.onap.so.bpmn.common.workflow.service.SDNCAdapterCallbackServiceImpl;
77 import org.onap.so.bpmn.common.workflow.service.VnfAdapterNotifyServiceImpl;
78 import org.onap.so.bpmn.common.workflow.service.WorkflowAsyncResource;
79 import org.onap.so.bpmn.common.workflow.service.WorkflowMessageResource;
80 import org.onap.so.bpmn.common.workflow.service.WorkflowResource;
81 import org.onap.so.bpmn.core.domain.Resource;
82 import org.onap.so.bpmn.core.domain.ServiceDecomposition;
83 import org.onap.so.logger.MsoLogger;
84 import org.springframework.beans.factory.annotation.Autowired;
85 import org.w3c.dom.Document;
86 import org.w3c.dom.Element;
87 import org.w3c.dom.Node;
88 import org.w3c.dom.NodeList;
89 import org.xml.sax.InputSource;
90 import org.xml.sax.SAXException;
95 * A base class for Workflow tests.
97 * WireMock response transformers may be specified by declaring public
98 * static fields with the @WorkflowTestTransformer annotation. For example:
100 * @WorkflowTestTransformer
101 * public static final ResponseTransformer sdncAdapterMockTransformer =
102 * new SDNCAdapterMockTransformer();
106 public abstract class WorkflowTest {
108 private static final MsoLogger msoLogger = MsoLogger.getMsoLogger(MsoLogger.Catalog.BPEL, WorkflowTest.class);
110 //TODO this is not used anymore, can maybe be removed
112 public ProcessEngineRule processEngineRule;
115 protected WorkflowResource workflowResourceSync;
118 protected ProcessEngine processEngine;
121 protected RuntimeService runtimeService;
124 protected HistoryService historyService;
127 private WorkflowAsyncResource workflowResource;
130 private WorkflowMessageResource workflowMessageResource;
133 SDNCAdapterCallbackServiceImpl callbackService;
135 * Content-Type for XML.
137 protected static final String XML = "application/xml";
140 * Content-Type for JSON.
142 protected static final String JSON = "application/json; charset=UTF-8";
144 private static final int timeout = 2000;
149 public WorkflowTest() throws RuntimeException {
153 * The current request ID. Normally set when an "invoke" method is called.
155 protected volatile String msoRequestId = null;
158 * The current service instance ID. Normally set when an "invoke" method
161 protected volatile String msoServiceInstanceId = null;
164 * Logs a test start method.
166 protected void logStart() {
167 msoLogger.debug("STARTED TEST");
171 * Logs a test end method.
173 protected void logEnd() {
174 msoLogger.debug("ENDED TEST");
178 * Invokes a subprocess.
179 * @param processKey the process key
180 * @param businessKey a unique key that will identify the process instance
181 * @param injectedVariables variables to inject into the process
183 protected void invokeSubProcess(String processKey, String businessKey, Map<String, Object> injectedVariables) {
184 RuntimeMXBean runtimeMxBean = ManagementFactory.getRuntimeMXBean();
185 List<String> arguments = runtimeMxBean.getInputArguments();
186 msoLogger.debug("JVM args = " + arguments);
188 msoRequestId = (String) injectedVariables.get("mso-request-id");
189 String requestId = (String) injectedVariables.get("msoRequestId");
191 if (msoRequestId == null && requestId == null) {
192 String msg = "mso-request-id variable was not provided";
193 msoLogger.debug(msg);
197 // Note: some scenarios don't have a service-instance-id, may be null
198 msoServiceInstanceId = (String) injectedVariables.get("mso-service-instance-id");
201 runtimeService.startProcessInstanceByKey(processKey, businessKey, injectedVariables);
204 protected String invokeSubProcess(String processKey, Map<String, Object> injectedVariables) {
205 RuntimeMXBean runtimeMxBean = ManagementFactory.getRuntimeMXBean();
206 List<String> arguments = runtimeMxBean.getInputArguments();
207 msoLogger.debug("JVM args = " + arguments);
209 msoRequestId = (String) injectedVariables.get("mso-request-id");
210 String requestId = (String) injectedVariables.get("msoRequestId");
212 if (msoRequestId == null && requestId == null) {
213 String msg = "mso-request-id variable was not provided";
214 msoLogger.debug(msg);
218 // Note: some scenarios don't have a service-instance-id, may be null
219 msoServiceInstanceId = (String) injectedVariables.get("mso-service-instance-id");
222 ProcessInstance processInstance = runtimeService.startProcessInstanceByKey(processKey, msoRequestId, injectedVariables);
223 return processInstance.getId();
227 * Invokes an asynchronous process.
228 * Errors are handled with junit assertions and will cause the test to fail.
229 * @param processKey the process key
230 * @param schemaVersion the API schema version, e.g. "v1"
231 * @param businessKey a unique key that will identify the process instance
232 * @param request the request
233 * @return a TestAsyncResponse object associated with the test
234 * @throws InterruptedException
236 protected TestAsyncResponse invokeAsyncProcess(String processKey,
237 String schemaVersion, String businessKey, String request) throws InterruptedException {
238 return invokeAsyncProcess(processKey, schemaVersion, businessKey, request, null);
242 * Invokes an asynchronous process.
243 * Errors are handled with junit assertions and will cause the test to fail.
244 * @param processKey the process key
245 * @param schemaVersion the API schema version, e.g. "v1"
246 * @param businessKey a unique key that will identify the process instance
247 * @param request the request
248 * @param injectedVariables optional variables to inject into the process
249 * @return a TestAsyncResponse object associated with the test
250 * @throws InterruptedException
252 protected TestAsyncResponse invokeAsyncProcess(String processKey,
253 String schemaVersion, String businessKey, String request,
254 Map<String, Object> injectedVariables) {
256 RuntimeMXBean runtimeMxBean = ManagementFactory.getRuntimeMXBean();
257 List<String> arguments = runtimeMxBean.getInputArguments();
258 msoLogger.debug("JVM args = " + arguments);
260 Map<String, Object> variables = createVariables(schemaVersion, businessKey,
261 request, injectedVariables, false);
262 VariableMapImpl variableMapImpl = createVariableMapImpl(variables);
264 msoLogger.debug("Sending " + request + " to " + processKey + " process");
266 TestAsyncResponse asyncResponse = new TestAsyncResponse();
268 asyncResponse.setResponse(workflowResource.startProcessInstanceByKey( processKey, variableMapImpl));
270 return asyncResponse;
274 * Invokes an asynchronous process.
275 * Errors are handled with junit assertions and will cause the test to fail.
276 * @param processKey the process key
277 * @param schemaVersion the API schema version, e.g. "v1"
278 * @param businessKey a unique key that will identify the process instance
279 * @param request the request
280 * @param injectedVariables optional variables to inject into the process
281 * @param serviceInstantiationModel indicates whether this method is being
282 * invoked for a flow that is designed using the service instantiation model
283 * @return a TestAsyncResponse object associated with the test
284 * @throws InterruptedException
286 protected Response invokeAsyncProcess(String processKey,
287 String schemaVersion, String businessKey, String request,
288 Map<String, Object> injectedVariables, boolean serviceInstantiationModel) {
290 RuntimeMXBean runtimeMxBean = ManagementFactory.getRuntimeMXBean();
291 List<String> arguments = runtimeMxBean.getInputArguments();
292 msoLogger.debug("JVM args = " + arguments);
294 Map<String, Object> variables = createVariables(schemaVersion, businessKey,
295 request, injectedVariables, serviceInstantiationModel);
296 VariableMapImpl variableMapImpl = createVariableMapImpl(variables);
298 msoLogger.debug("Sending " + request + " to " + processKey + " process");
300 return workflowResource.startProcessInstanceByKey( processKey, variableMapImpl);
305 * Private helper method that creates a variable map for a request.
306 * Errors are handled with junit assertions and will cause the test to fail.
307 * @param schemaVersion the API schema version, e.g. "v1"
308 * @param businessKey a unique key that will identify the process instance
309 * @param request the request
310 * @param injectedVariables optional variables to inject into the process
311 * @param serviceInstantiationModel indicates whether this method is being
312 * invoked for a flow that is designed using the service instantiation model
313 * @return a variable map
315 private Map<String, Object> createVariables(String schemaVersion,
316 String businessKey, String request, Map<String, Object> injectedVariables,
317 boolean serviceInstantiationModel) {
319 Map<String, Object> variables = new HashMap<>();
321 // These variables may be overridded by injected variables.
322 variables.put("mso-service-request-timeout", "180");
323 variables.put("isDebugLogEnabled", "true");
325 // These variables may not be overridded by injected variables.
326 String[] notAllowed = new String[] {
327 "mso-schema-version",
331 "mso-service-instance-id"
334 if (injectedVariables != null) {
335 for (String key : injectedVariables.keySet()) {
336 for (String var : notAllowed) {
337 if (var.equals(key)) {
338 String msg = "Cannot specify " + var + " in injected variables";
339 msoLogger.debug(msg);
344 variables.put(key, injectedVariables.get(key));
348 variables.put("mso-schema-version", schemaVersion);
349 variables.put("mso-business-key", businessKey);
350 variables.put("bpmnRequest", request);
352 if (serviceInstantiationModel) {
355 * The request ID and the service instance ID are generated for flows
356 * that follow the service instantiation model unless "requestId" and
357 * "serviceInstanceId" are injected variables.
361 msoRequestId = (String) injectedVariables.get("requestId");
362 variables.put("mso-request-id", msoRequestId);
363 msoServiceInstanceId = (String) injectedVariables.get("serviceInstanceId");
364 variables.put("mso-service-instance-id", msoServiceInstanceId);
368 if (msoRequestId == null || msoRequestId.trim().equals("")) {
369 msoLogger.debug("No requestId element in injectedVariables");
370 variables.put("mso-request-id", UUID.randomUUID().toString());
372 if (msoServiceInstanceId == null || msoServiceInstanceId.trim().equals("")) {
373 msoLogger.debug("No seviceInstanceId element in injectedVariables");
374 variables.put("mso-service-instance-id", UUID.randomUUID().toString());
378 msoRequestId = getXMLTextElement(request, "request-id");
380 if (msoRequestId == null) {
381 //check in injected variables
383 msoRequestId = (String) injectedVariables.get("requestId");
387 if (msoRequestId == null || msoRequestId.trim().equals("")) {
388 String msg = "No request-id element in " + request;
389 msoLogger.debug(msg);
394 variables.put("mso-request-id", msoRequestId);
396 // Note: some request types don't have a service-instance-id
397 msoServiceInstanceId = getXMLTextElement(request, "service-instance-id");
399 if (msoServiceInstanceId != null) {
400 variables.put("mso-service-instance-id", msoServiceInstanceId);
408 * Private helper method that creates a camunda VariableMapImpl from a simple
410 * @param variables the simple variable map
411 * @return a VariableMap
413 private VariableMapImpl createVariableMapImpl(Map<String, Object> variables) {
414 Map<String, Object> wrappedVariables = new HashMap<>();
416 for (String key : variables.keySet()) {
417 Object value = variables.get(key);
418 wrappedVariables.put(key, wrapVariableValue(value));
421 VariableMapImpl variableMapImpl = new VariableMapImpl();
422 variableMapImpl.put("variables", wrappedVariables);
423 return variableMapImpl;
427 * Private helper method that wraps a variable value for inclusion in a
428 * camunda VariableMapImpl.
429 * @param value the variable value
430 * @return the wrapped variable
432 private Map<String, Object> wrapVariableValue(Object value) {
433 HashMap<String, Object> valueMap = new HashMap<>();
434 valueMap.put("value", value);
439 * Receives a response from an asynchronous process.
440 * Errors are handled with junit assertions and will cause the test to fail.
441 * @param businessKey the process business key
442 * @param asyncResponse the TestAsyncResponse object associated with the test
443 * @param timeout the timeout in milliseconds
444 * @return the WorkflowResponse
446 protected WorkflowResponse receiveResponse(String businessKey,
447 TestAsyncResponse asyncResponse, long timeout) {
448 msoLogger.debug("Waiting " + timeout + "ms for process with business key " + businessKey
449 + " to send a response");
451 long now = System.currentTimeMillis() + timeout;
452 long endTime = now + timeout;
454 while (now <= endTime) {
455 Response response = asyncResponse.getResponse();
457 if (response != null) {
458 msoLogger.debug("Received a response from process with business key " + businessKey);
460 Object entity = response.getEntity();
462 if (!(entity instanceof WorkflowResponse)) {
463 String msg = "Response entity is " +
464 (entity == null ? "null" : entity.getClass().getName()) +
465 ", expected WorkflowResponse";
466 msoLogger.debug(msg);
468 return null; // unreachable
471 return (WorkflowResponse) entity;
476 } catch (InterruptedException e) {
477 String msg = "Interrupted waiting for a response from process with business key " +
479 msoLogger.debug(msg);
481 return null; // unreachable
484 now = System.currentTimeMillis();
487 String msg = "No response received from process with business key " + businessKey +
488 " within " + timeout + "ms";
489 msoLogger.debug(msg);
490 fail("Process with business key " + businessKey + " did not end within 10000ms");
491 return null; // unreachable
495 * Runs a program to inject SDNC callback data into the test environment.
496 * A program is essentially just a list of keys that identify callback data
497 * to be injected, in sequence. An example program:
499 * reserve, assign, delete:ERR
501 * Errors are handled with junit assertions and will cause the test to fail.
502 * @param callbacks an object containing callback data for the program
503 * @param program the program to execute
505 protected void injectSDNCRestCallbacks(CallbackSet callbacks, String program) {
507 String[] cmds = program.replaceAll("\\s+", "").split(",");
509 for (String cmd : cmds) {
511 String modifier = "STD";
513 if (cmd.contains(":")) {
514 String[] parts = cmd.split(":");
519 String content = null;
520 String contentType = null;
522 if ("STD".equals(modifier)) {
523 CallbackData callbackData = callbacks.get(action);
525 if (callbackData == null) {
526 String msg = "No callback defined for '" + action + "' SDNC request";
527 msoLogger.debug(msg);
531 content = callbackData.getContent();
532 contentType = callbackData.getContentType();
533 } else if ("ERR".equals(modifier)) {
534 content = "{\"SDNCServiceError\":{\"sdncRequestId\":\"((REQUEST-ID))\",\"responseCode\":\"500\",\"responseMessage\":\"SIMULATED ERROR FROM SDNC ADAPTER\",\"ackFinalIndicator\":\"Y\"}}";
537 String msg = "Invalid SDNC program modifier: '" + modifier + "'";
538 msoLogger.debug(msg);
542 if (contentType == null) {
543 // Default for backward compatibility with existing tests.
547 if (!injectSDNCRestCallback(contentType, content, 10000)) {
548 fail("Failed to inject SDNC '" + action + "' callback");
553 } catch (InterruptedException e) {
554 fail("Interrupted after injection of SDNC '" + action + "' callback");
560 * Runs a program to inject SDNC events into the test environment.
561 * A program is essentially just a list of keys that identify event data
562 * to be injected, in sequence. An example program:
566 * NOTE: Each callback must have a message type associated with it, e.g.
568 * Errors are handled with junit assertions and will cause the test to fail.
569 * @param callbacks an object containing event data for the program
570 * @param program the program to execute
572 protected void injectSDNCEvents(CallbackSet callbacks, String program) {
573 injectWorkflowMessages(callbacks, program);
577 * Runs a program to inject SDNC callback data into the test environment.
578 * A program is essentially just a list of keys that identify callback data
579 * to be injected, in sequence. An example program:
581 * reserve, assign, delete:ERR
583 * Errors are handled with junit assertions and will cause the test to fail.
584 * Uses the static/default timeout value for backward compatibility.
585 * @param callbacks an object containing callback data for the program
586 * @param program the program to execute
588 protected void injectSDNCCallbacks(CallbackSet callbacks, String program) {
589 injectSDNCCallbacks(callbacks, program, timeout);
593 * Runs a program to inject SDNC callback data into the test environment.
594 * A program is essentially just a list of keys that identify callback data
595 * to be injected, in sequence. An example program:
597 * reserve, assign, delete:ERR
599 * Errors are handled with junit assertions and will cause the test to fail.
600 * @param callbacks an object containing callback data for the program
601 * @param program the program to execute
602 * @param timeout a timeout value to wait for the callback
604 protected void injectSDNCCallbacks(CallbackSet callbacks, String program, int timeout) {
606 String[] cmds = program.replaceAll("\\s+", "").split(",");
608 for (String cmd : cmds) {
610 String modifier = "STD";
612 if (cmd.contains(":")) {
613 String[] parts = cmd.split(":");
618 String content = null;
620 String respMsg = "OK";
622 if ("STD".equals(modifier)) {
623 CallbackData callbackData = callbacks.get(action);
625 if (callbackData == null) {
626 String msg = "No callback defined for '" + action + "' SDNC request";
627 msoLogger.debug(msg);
631 content = callbackData.getContent();
634 } else if ("CREATED".equals(modifier)) {
635 CallbackData callbackData = callbacks.get(action);
637 if (callbackData == null) {
638 String msg = "No callback defined for '" + action + "' SDNC request";
639 msoLogger.debug(msg);
643 content = callbackData.getContent();
646 } else if ("ERR".equals(modifier)) {
647 content = "<svc-request-id>((REQUEST-ID))</svc-request-id><response-code>500</response-code><response-message>SIMULATED ERROR FROM SDNC ADAPTER</response-message>";
649 respMsg = "SERVER ERROR";
651 String msg = "Invalid SDNC program modifier: '" + modifier + "'";
652 msoLogger.debug(msg);
656 if (!injectSDNCCallback(respCode, respMsg, content, 10000)) {
657 fail("Failed to inject SDNC '" + action + "' callback");
662 } catch (InterruptedException e) {
663 fail("Interrupted after injection of SDNC '" + action + "' callback");
669 * Runs a program to inject VNF adapter REST callback data into the test environment.
670 * A program is essentially just a list of keys that identify callback data
671 * to be injected, in sequence. An example program:
675 * Errors are handled with junit assertions and will cause the test to fail.
676 * @param callbacks an object containing callback data for the program
677 * @param program the program to execute
679 protected void injectVNFRestCallbacks(CallbackSet callbacks, String program) {
681 String[] cmds = program.replaceAll("\\s+", "").split(",");
683 for (String cmd : cmds) {
685 String modifier = "STD";
687 if (cmd.contains(":")) {
688 String[] parts = cmd.split(":");
693 String content = null;
694 String contentType = null;
696 if ("STD".equals(modifier)) {
697 CallbackData callbackData = callbacks.get(action);
699 if (callbackData == null) {
700 String msg = "No callback defined for '" + action + "' VNF REST request";
701 msoLogger.debug(msg);
705 content = callbackData.getContent();
706 contentType = callbackData.getContentType();
707 } else if ("ERR".equals(modifier)) {
708 content = "SIMULATED ERROR FROM VNF ADAPTER";
709 contentType = "text/plain";
711 String msg = "Invalid VNF REST program modifier: '" + modifier + "'";
712 msoLogger.debug(msg);
716 if (contentType == null) {
717 // Default for backward compatibility with existing tests.
721 if (!injectVnfAdapterRestCallback(contentType, content, 10000)) {
722 fail("Failed to inject VNF REST '" + action + "' callback");
727 } catch (InterruptedException e) {
728 fail("Interrupted after injection of VNF REST '" + action + "' callback");
734 * Runs a program to inject VNF callback data into the test environment.
735 * A program is essentially just a list of keys that identify callback data
736 * to be injected, in sequence. An example program:
738 * createVnf, deleteVnf
740 * Errors are handled with junit assertions and will cause the test to fail.
741 * @param callbacks an object containing callback data for the program
742 * @param program the program to execute
744 protected void injectVNFCallbacks(CallbackSet callbacks, String program) {
746 String[] cmds = program.replaceAll("\\s+", "").split(",");
748 for (String cmd : cmds) {
750 String modifier = "STD";
752 if (cmd.contains(":")) {
753 String[] parts = cmd.split(":");
758 String content = null;
760 if ("STD".equals(modifier)) {
761 CallbackData callbackData = callbacks.get(action);
763 if (callbackData == null) {
764 String msg = "No callback defined for '" + action + "' VNF request";
765 msoLogger.debug(msg);
769 content = callbackData.getContent();
770 } else if ("ERR".equals(modifier)) {
771 String msg = "Currently unsupported VNF program modifier: '" + modifier + "'";
772 msoLogger.debug(msg);
775 String msg = "Invalid VNF program modifier: '" + modifier + "'";
776 msoLogger.debug(msg);
780 boolean injected = false;
782 if (content.contains("createVnfNotification")) {
783 injected = injectCreateVNFCallback(content, 10000);
784 } else if (content.contains("deleteVnfNotification")) {
785 injected = injectDeleteVNFCallback(content, 10000);
786 } else if (content.contains("updateVnfNotification")) {
787 injected = injectUpdateVNFCallback(content, 10000);
791 String msg = "Failed to inject VNF '" + action + "' callback";
792 msoLogger.debug(msg);
798 } catch (InterruptedException e) {
799 fail("Interrupted after injection of VNF '" + action + "' callback");
805 * Waits for the number of running processes with the specified process
806 * definition key to equal a particular count.
807 * @param processKey the process definition key
808 * @param count the desired count
809 * @param timeout the timeout in milliseconds
811 protected void waitForRunningProcessCount(String processKey, int count, long timeout) {
812 msoLogger.debug("Waiting " + timeout + "ms for there to be " + count + " "
813 + processKey + " instances");
815 long now = System.currentTimeMillis() + timeout;
816 long endTime = now + timeout;
819 while (now <= endTime) {
820 int actual = runtimeService
821 .createProcessInstanceQuery()
822 .processDefinitionKey(processKey)
825 if (actual != last) {
826 msoLogger.debug("There are now " + actual + " "
827 + processKey + " instances");
831 if (actual == count) {
837 } catch (InterruptedException e) {
838 String msg = "Interrupted waiting for there to be " + count + " "
839 + processKey + " instances";
840 msoLogger.debug(msg);
844 now = System.currentTimeMillis();
847 String msg = "Timed out waiting for there to be " + count + " "
848 + processKey + " instances";
849 msoLogger.debug(msg);
854 * Waits for the specified process variable to be set.
855 * @param processKey the process definition key
856 * @param variable the variable name
857 * @param timeout the timeout in milliseconds
858 * @return the variable value, or null if it cannot be obtained
859 * in the specified time
861 protected Object getProcessVariable(String processKey, String variable,
864 msoLogger.debug("Waiting " + timeout + "ms for "
865 + processKey + "." + variable + " to be set");
867 long now = System.currentTimeMillis() + timeout;
868 long endTime = now + timeout;
870 ProcessInstance processInstance = null;
873 while (value == null) {
875 if (processInstance == null) {
876 msoLogger.debug("Timed out waiting for "
877 + processKey + " to start");
879 msoLogger.debug("Timed out waiting for "
880 + processKey + "[" + processInstance.getId()
881 + "]." + variable + " to be set");
887 if (processInstance == null) {
888 processInstance = runtimeService
889 .createProcessInstanceQuery()
890 .processDefinitionKey(processKey)
894 if (processInstance != null) {
895 value = runtimeService
896 .getVariable(processInstance.getId(), variable);
901 } catch (InterruptedException e) {
902 msoLogger.debug("Interrupted waiting for "
903 + processKey + "." + variable + " to be set");
907 now = System.currentTimeMillis();
910 msoLogger.debug(processKey + "["
911 + processInstance.getId() + "]." + variable + "="
918 * Injects a single SDNC adapter callback request. The specified callback data
919 * may contain the placeholder string ((REQUEST-ID)) which is replaced with
920 * the actual SDNC request ID. Note: this is not the requestId in the original
922 * @param contentType the HTTP content type for the callback
923 * @param content the content of the callback
924 * @param timeout the timeout in milliseconds
925 * @return true if the callback could be injected, false otherwise
927 protected boolean injectSDNCRestCallback(String contentType, String content, long timeout) {
928 String sdncRequestId = (String) getProcessVariable("SDNCAdapterRestV1",
929 "SDNCAResponse_CORRELATOR", timeout);
931 if (sdncRequestId == null) {
932 sdncRequestId = (String) getProcessVariable("SDNCAdapterRestV2",
933 "SDNCAResponse_CORRELATOR", timeout);
936 if (sdncRequestId == null) {
940 content = content.replace("((REQUEST-ID))", sdncRequestId);
941 // Deprecated usage. All test code should switch to the (( ... )) syntax.
942 content = content.replace("{{REQUEST-ID}}", sdncRequestId);
944 msoLogger.debug("Injecting SDNC adapter callback");
946 Response response = workflowMessageResource.deliver(contentType, "SDNCAResponse", sdncRequestId, content);
947 msoLogger.debug("Workflow response to SDNC adapter callback: " + response);
952 * Injects a single SDNC adapter callback request. The specified callback data
953 * may contain the placeholder string ((REQUEST-ID)) which is replaced with
954 * the actual SDNC request ID. Note: this is not the requestId in the original
956 * @param content the content of the callback
957 * @param respCode the response code (normally 200)
958 * @param respMsg the response message (normally "OK")
959 * @param timeout the timeout in milliseconds
960 * @return true if the callback could be injected, false otherwise
962 protected boolean injectSDNCCallback(int respCode, String respMsg,
963 String content, long timeout) {
965 String sdncRequestId = (String) getProcessVariable("sdncAdapter",
966 "SDNCA_requestId", timeout);
968 if (sdncRequestId == null) {
972 content = content.replace("((REQUEST-ID))", sdncRequestId);
973 // Deprecated usage. All test code should switch to the (( ... )) syntax.
974 content = content.replace("{{REQUEST-ID}}", sdncRequestId);
976 // TODO this needs to be fixed. It is causing double tags and content
977 // Need to parse content before setting below since content includes not just RequestData or modify callback files to only contain RequestData contents.
979 msoLogger.debug("Injecting SDNC adapter callback");
980 CallbackHeader callbackHeader = new CallbackHeader();
981 callbackHeader.setRequestId(sdncRequestId);
982 callbackHeader.setResponseCode(String.valueOf(respCode));
983 callbackHeader.setResponseMessage(respMsg);
984 SDNCAdapterCallbackRequest sdncAdapterCallbackRequest = new SDNCAdapterCallbackRequest();
985 sdncAdapterCallbackRequest.setCallbackHeader(callbackHeader);
986 sdncAdapterCallbackRequest.setRequestData(content);
987 SDNCAdapterResponse sdncAdapterResponse = callbackService.sdncAdapterCallback(sdncAdapterCallbackRequest);
988 msoLogger.debug("Workflow response to SDNC adapter callback: " + sdncAdapterResponse);
994 * Injects a single VNF adapter callback request. The specified callback data
995 * may contain the placeholder string ((MESSAGE-ID)) which is replaced with
996 * the actual message ID. Note: this is not the requestId in the original
998 * @param contentType the HTTP content type for the callback
999 * @param content the content of the callback
1000 * @param timeout the timeout in milliseconds
1001 * @return true if the callback could be injected, false otherwise
1003 protected boolean injectVnfAdapterRestCallback(String contentType, String content, long timeout) {
1004 String messageId = (String) getProcessVariable("vnfAdapterRestV1",
1005 "VNFAResponse_CORRELATOR", timeout);
1007 if (messageId == null) {
1011 content = content.replace("((MESSAGE-ID))", messageId);
1012 // Deprecated usage. All test code should switch to the (( ... )) syntax.
1013 content = content.replace("{{MESSAGE-ID}}", messageId);
1015 msoLogger.debug("Injecting VNF adapter callback");
1017 Response response = workflowMessageResource.deliver(contentType, "VNFAResponse", messageId, content);
1018 msoLogger.debug("Workflow response to VNF adapter callback: " + response);
1023 * Injects a Create VNF adapter callback request. The specified callback data
1024 * may contain the placeholder string ((MESSAGE-ID)) which is replaced with
1025 * the actual message ID. It may also contain the placeholder string
1026 * ((REQUEST-ID)) which is replaced request ID of the original MSO request.
1027 * @param content the content of the callback
1028 * @param timeout the timeout in milliseconds
1029 * @return true if the callback could be injected, false otherwise
1030 * @throws JAXBException if the content does not adhere to the schema
1032 protected boolean injectCreateVNFCallback(String content, long timeout) {
1034 String messageId = (String) getProcessVariable("vnfAdapterCreateV1",
1035 "VNFC_messageId", timeout);
1037 if (messageId == null) {
1041 content = content.replace("((MESSAGE-ID))", messageId);
1042 // Deprecated usage. All test code should switch to the (( ... )) syntax.
1043 content = content.replace("{{MESSAGE-ID}}", messageId);
1045 if(content.contains("((REQUEST-ID))")){
1046 content = content.replace("((REQUEST-ID))", msoRequestId);
1047 // Deprecated usage. All test code should switch to the (( ... )) syntax.
1048 content = content.replace("{{REQUEST-ID}}", msoRequestId);
1051 msoLogger.debug("Injecting VNF adapter callback");
1053 // Is it possible to unmarshal this with JAXB? I couldn't.
1055 CreateVnfNotification createVnfNotification = new CreateVnfNotification();
1056 XPathTool xpathTool = new VnfNotifyXPathTool();
1057 xpathTool.setXML(content);
1060 String completed = xpathTool.evaluate(
1061 "/tns:createVnfNotification/tns:completed/text()");
1062 createVnfNotification.setCompleted("true".equals(completed));
1064 String vnfId = xpathTool.evaluate(
1065 "/tns:createVnfNotification/tns:vnfId/text()");
1066 createVnfNotification.setVnfId(vnfId);
1068 NodeList entries = (NodeList) xpathTool.evaluate(
1069 "/tns:createVnfNotification/tns:outputs/tns:entry",
1070 XPathConstants.NODESET);
1072 CreateVnfNotificationOutputs outputs = new CreateVnfNotificationOutputs();
1074 for (int i = 0; i < entries.getLength(); i++) {
1075 Node node = entries.item(i);
1077 if (node.getNodeType() == Node.ELEMENT_NODE) {
1078 Element entry = (Element) node;
1079 String key = entry.getElementsByTagNameNS("*", "key").item(0).getTextContent();
1080 String value = entry.getElementsByTagNameNS("*", "value").item(0).getTextContent();
1081 outputs.add(key, value);
1085 createVnfNotification.setOutputs(outputs);
1087 VnfRollback rollback = new VnfRollback();
1089 String cloudSiteId = xpathTool.evaluate(
1090 "/tns:createVnfNotification/tns:rollback/tns:cloudSiteId/text()");
1091 rollback.setCloudSiteId(cloudSiteId);
1093 String requestId = xpathTool.evaluate(
1094 "/tns:createVnfNotification/tns:rollback/tns:msoRequest/tns:requestId/text()");
1095 String serviceInstanceId = xpathTool.evaluate(
1096 "/tns:createVnfNotification/tns:rollback/tns:msoRequest/tns:serviceInstanceId/text()");
1098 if (requestId != null || serviceInstanceId != null) {
1099 MsoRequest msoRequest = new MsoRequest();
1100 msoRequest.setRequestId(requestId);
1101 msoRequest.setServiceInstanceId(serviceInstanceId);
1102 rollback.setMsoRequest(msoRequest);
1105 String tenantCreated = xpathTool.evaluate(
1106 "/tns:createVnfNotification/tns:rollback/tns:tenantCreated/text()");
1107 rollback.setTenantCreated("true".equals(tenantCreated));
1109 String tenantId = xpathTool.evaluate(
1110 "/tns:createVnfNotification/tns:rollback/tns:tenantId/text()");
1111 rollback.setTenantId(tenantId);
1113 String vnfCreated = xpathTool.evaluate(
1114 "/tns:createVnfNotification/tns:rollback/tns:vnfCreated/text()");
1115 rollback.setVnfCreated("true".equals(vnfCreated));
1117 String rollbackVnfId = xpathTool.evaluate(
1118 "/tns:createVnfNotification/tns:rollback/tns:vnfId/text()");
1119 rollback.setVnfId(rollbackVnfId);
1121 createVnfNotification.setRollback(rollback);
1123 } catch (Exception e) {
1124 msoLogger.debug("Failed to unmarshal VNF callback content:");
1125 msoLogger.debug(content);
1129 VnfAdapterNotifyServiceImpl notifyService = new VnfAdapterNotifyServiceImpl();
1132 notifyService.createVnfNotification(
1134 createVnfNotification.isCompleted(),
1135 createVnfNotification.getException(),
1136 createVnfNotification.getErrorMessage(),
1137 createVnfNotification.getVnfId(),
1138 createVnfNotification.getOutputs(),
1139 createVnfNotification.getRollback());
1145 * Injects a Delete VNF adapter callback request. The specified callback data
1146 * may contain the placeholder string ((MESSAGE-ID)) which is replaced with
1147 * the actual message ID. It may also contain the placeholder string
1148 * ((REQUEST-ID)) which is replaced request ID of the original MSO request.
1149 * @param content the content of the callback
1150 * @param timeout the timeout in milliseconds
1151 * @return true if the callback could be injected, false otherwise
1152 * @throws JAXBException if the content does not adhere to the schema
1154 protected boolean injectDeleteVNFCallback(String content, long timeout) {
1156 String messageId = (String) getProcessVariable("vnfAdapterDeleteV1",
1157 "VNFDEL_uuid", timeout);
1159 if (messageId == null) {
1163 content = content.replace("((MESSAGE-ID))", messageId);
1164 // Deprecated usage. All test code should switch to the (( ... )) syntax.
1165 content = content.replace("{{MESSAGE-ID}}", messageId);
1167 msoLogger.debug("Injecting VNF adapter delete callback");
1169 // Is it possible to unmarshal this with JAXB? I couldn't.
1171 DeleteVnfNotification deleteVnfNotification = new DeleteVnfNotification();
1172 XPathTool xpathTool = new VnfNotifyXPathTool();
1173 xpathTool.setXML(content);
1176 String completed = xpathTool.evaluate(
1177 "/tns:deleteVnfNotification/tns:completed/text()");
1178 deleteVnfNotification.setCompleted("true".equals(completed));
1179 // if notification failure, set the exception and error message
1180 if (deleteVnfNotification.isCompleted() == false) {
1181 deleteVnfNotification.setException(MsoExceptionCategory.INTERNAL);
1182 deleteVnfNotification.setErrorMessage(xpathTool.evaluate(
1183 "/tns:deleteVnfNotification/tns:errorMessage/text()")) ;
1186 } catch (Exception e) {
1187 msoLogger.debug("Failed to unmarshal VNF Delete callback content:");
1188 msoLogger.debug(content);
1192 VnfAdapterNotifyServiceImpl notifyService = new VnfAdapterNotifyServiceImpl();
1195 notifyService.deleteVnfNotification(
1197 deleteVnfNotification.isCompleted(),
1198 deleteVnfNotification.getException(),
1199 deleteVnfNotification.getErrorMessage());
1205 * Injects a Update VNF adapter callback request. The specified callback data
1206 * may contain the placeholder string ((MESSAGE-ID)) which is replaced with
1207 * the actual message ID. It may also contain the placeholder string
1208 * ((REQUEST-ID)) which is replaced request ID of the original MSO request.
1209 * @param content the content of the callback
1210 * @param timeout the timeout in milliseconds
1211 * @return true if the callback could be injected, false otherwise
1212 * @throws JAXBException if the content does not adhere to the schema
1214 protected boolean injectUpdateVNFCallback(String content, long timeout) {
1216 String messageId = (String) getProcessVariable("vnfAdapterUpdate",
1217 "VNFU_messageId", timeout);
1219 if (messageId == null) {
1223 content = content.replace("((MESSAGE-ID))", messageId);
1224 // Deprecated usage. All test code should switch to the (( ... )) syntax.
1225 content = content.replace("{{MESSAGE-ID}}", messageId);
1227 content = content.replace("((REQUEST-ID))", msoRequestId);
1228 // Deprecated usage. All test code should switch to the (( ... )) syntax.
1229 content = content.replace("{{REQUEST-ID}}", msoRequestId);
1231 msoLogger.debug("Injecting VNF adapter callback");
1233 // Is it possible to unmarshal this with JAXB? I couldn't.
1235 UpdateVnfNotification updateVnfNotification = new UpdateVnfNotification();
1236 XPathTool xpathTool = new VnfNotifyXPathTool();
1237 xpathTool.setXML(content);
1240 String completed = xpathTool.evaluate(
1241 "/tns:updateVnfNotification/tns:completed/text()");
1242 updateVnfNotification.setCompleted("true".equals(completed));
1244 NodeList entries = (NodeList) xpathTool.evaluate(
1245 "/tns:updateVnfNotification/tns:outputs/tns:entry",
1246 XPathConstants.NODESET);
1248 UpdateVnfNotificationOutputs outputs = new UpdateVnfNotificationOutputs();
1250 for (int i = 0; i < entries.getLength(); i++) {
1251 Node node = entries.item(i);
1253 if (node.getNodeType() == Node.ELEMENT_NODE) {
1254 Element entry = (Element) node;
1255 String key = entry.getElementsByTagNameNS("*", "key").item(0).getTextContent();
1256 String value = entry.getElementsByTagNameNS("*", "value").item(0).getTextContent();
1257 outputs.add(key, value);
1261 updateVnfNotification.setOutputs(outputs);
1263 VnfRollback rollback = new VnfRollback();
1265 String cloudSiteId = xpathTool.evaluate(
1266 "/tns:updateVnfNotification/tns:rollback/tns:cloudSiteId/text()");
1267 rollback.setCloudSiteId(cloudSiteId);
1269 String requestId = xpathTool.evaluate(
1270 "/tns:updateVnfNotification/tns:rollback/tns:msoRequest/tns:requestId/text()");
1271 String serviceInstanceId = xpathTool.evaluate(
1272 "/tns:updateVnfNotification/tns:rollback/tns:msoRequest/tns:serviceInstanceId/text()");
1274 if (requestId != null || serviceInstanceId != null) {
1275 MsoRequest msoRequest = new MsoRequest();
1276 msoRequest.setRequestId(requestId);
1277 msoRequest.setServiceInstanceId(serviceInstanceId);
1278 rollback.setMsoRequest(msoRequest);
1281 String tenantCreated = xpathTool.evaluate(
1282 "/tns:updateVnfNotification/tns:rollback/tns:tenantCreated/text()");
1283 rollback.setTenantCreated("true".equals(tenantCreated));
1285 String tenantId = xpathTool.evaluate(
1286 "/tns:updateVnfNotification/tns:rollback/tns:tenantId/text()");
1287 rollback.setTenantId(tenantId);
1289 String vnfCreated = xpathTool.evaluate(
1290 "/tns:updateVnfNotification/tns:rollback/tns:vnfCreated/text()");
1291 rollback.setVnfCreated("true".equals(vnfCreated));
1293 String rollbackVnfId = xpathTool.evaluate(
1294 "/tns:updateVnfNotification/tns:rollback/tns:vnfId/text()");
1295 rollback.setVnfId(rollbackVnfId);
1297 updateVnfNotification.setRollback(rollback);
1299 } catch (Exception e) {
1300 msoLogger.debug("Failed to unmarshal VNF callback content:");
1301 msoLogger.debug(content);
1305 VnfAdapterNotifyServiceImpl notifyService = new VnfAdapterNotifyServiceImpl();
1308 notifyService.updateVnfNotification(
1310 updateVnfNotification.isCompleted(),
1311 updateVnfNotification.getException(),
1312 updateVnfNotification.getErrorMessage(),
1313 updateVnfNotification.getOutputs(),
1314 updateVnfNotification.getRollback());
1320 * Runs a program to inject workflow messages into the test environment.
1321 * A program is essentially just a list of keys that identify event data
1322 * to be injected, in sequence. An example program:
1326 * Errors are handled with junit assertions and will cause the test to fail.
1327 * NOTE: Each callback must have a workflow message type associated with it.
1328 * @param callbacks an object containing event data for the program
1329 * @param program the program to execute
1331 protected void injectWorkflowMessages(CallbackSet callbacks, String program) {
1333 String[] cmds = program.replaceAll("\\s+", "").split(",");
1335 for (String cmd : cmds) {
1336 String action = cmd;
1337 String modifier = "STD";
1339 if (cmd.contains(":")) {
1340 String[] parts = cmd.split(":");
1342 modifier = parts[1];
1345 String messageType = null;
1346 String content = null;
1347 String contentType = null;
1349 if ("STD".equals(modifier)) {
1350 CallbackData callbackData = callbacks.get(action);
1352 if (callbackData == null) {
1353 String msg = "No '" + action + "' workflow message callback is defined";
1354 msoLogger.debug(msg);
1358 messageType = callbackData.getMessageType();
1360 if (messageType == null || messageType.trim().equals("")) {
1361 String msg = "No workflow message type is defined in the '" + action + "' callback";
1362 msoLogger.debug(msg);
1366 content = callbackData.getContent();
1367 contentType = callbackData.getContentType();
1369 String msg = "Invalid workflow message program modifier: '" + modifier + "'";
1370 msoLogger.debug(msg);
1374 if (!injectWorkflowMessage(contentType, messageType, content, 10000)) {
1375 fail("Failed to inject '" + action + "' workflow message");
1380 } catch (InterruptedException e) {
1381 fail("Interrupted after injection of '" + action + "' workflow message");
1387 * Injects a workflow message. The specified callback data may contain the
1388 * placeholder string ((CORRELATOR)) which is replaced with the actual
1390 * @param contentType the HTTP contentType for the message (possibly null)
1391 * @param messageType the message type
1392 * @param content the message content (possibly null)
1393 * @param timeout the timeout in milliseconds
1394 * @return true if the message could be injected, false otherwise
1396 protected boolean injectWorkflowMessage(String contentType, String messageType, String content, long timeout) {
1397 String correlator = (String) getProcessVariable("ReceiveWorkflowMessage",
1398 messageType + "_CORRELATOR", timeout);
1400 if (correlator == null) {
1404 if (content != null) {
1405 content = content.replace("((CORRELATOR))", correlator);
1408 msoLogger.debug("Injecting " + messageType + " message");
1410 Response response = workflowMessageResource.deliver(contentType, messageType, correlator, content);
1411 msoLogger.debug("Workflow response to " + messageType + " message: " + response);
1416 * Runs a program to inject sniro workflow messages into the test environment.
1417 * A program is essentially just a list of keys that identify event data
1418 * to be injected, in sequence. For more details, see
1419 * injectSNIROCallbacks(String contentType, String messageType, String content, long timeout)
1421 * Errors are handled with junit assertions and will cause the test to fail.
1422 * NOTE: Each callback must have a workflow message type associated with it.
1424 * @param callbacks an object containing event data for the program
1425 * @param program the program to execute
1427 protected void injectSNIROCallbacks(CallbackSet callbacks, String program) {
1429 String[] cmds = program.replaceAll("\\s+", "").split(",");
1431 for (String cmd : cmds) {
1432 String action = cmd;
1433 String modifier = "STD";
1435 if (cmd.contains(":")) {
1436 String[] parts = cmd.split(":");
1438 modifier = parts[1];
1441 String messageType = null;
1442 String content = null;
1443 String contentType = null;
1445 if ("STD".equals(modifier)) {
1446 CallbackData callbackData = callbacks.get(action);
1448 if (callbackData == null) {
1449 String msg = "No '" + action + "' workflow message callback is defined";
1450 msoLogger.debug(msg);
1454 messageType = callbackData.getMessageType();
1456 if (messageType == null || messageType.trim().equals("")) {
1457 String msg = "No workflow message type is defined in the '" + action + "' callback";
1458 msoLogger.debug(msg);
1462 content = callbackData.getContent();
1463 contentType = callbackData.getContentType();
1465 String msg = "Invalid workflow message program modifier: '" + modifier + "'";
1466 msoLogger.debug(msg);
1470 if (!injectSNIROCallbacks(contentType, messageType, content, 10000)) {
1471 fail("Failed to inject '" + action + "' workflow message");
1476 } catch (InterruptedException e) {
1477 fail("Interrupted after injection of '" + action + "' workflow message");
1483 * Injects a sniro workflow message. The specified callback response may
1484 * contain the placeholder strings ((CORRELATOR)) and ((SERVICE_RESOURCE_ID))
1485 * The ((CORRELATOR)) is replaced with the actual correlator value from the
1486 * request. The ((SERVICE_RESOURCE_ID)) is replaced with the actual serviceResourceId
1487 * value from the sniro request. Currently this only works with sniro request
1488 * that contain only 1 resource.
1490 * @param contentType the HTTP contentType for the message (possibly null)
1491 * @param messageType the message type
1492 * @param content the message content (possibly null)
1493 * @param timeout the timeout in milliseconds
1494 * @return true if the message could be injected, false otherwise
1496 protected boolean injectSNIROCallbacks(String contentType, String messageType, String content, long timeout) {
1497 String correlator = (String) getProcessVariable("ReceiveWorkflowMessage",
1498 messageType + "_CORRELATOR", timeout);
1500 if (correlator == null) {
1503 if (content != null) {
1504 content = content.replace("((CORRELATOR))", correlator);
1505 if(messageType.equalsIgnoreCase("SNIROResponse")){
1506 ServiceDecomposition decomp = (ServiceDecomposition) getProcessVariable("Homing", "serviceDecomposition", timeout);
1507 List<Resource> resourceList = decomp.getServiceResources();
1508 if(resourceList.size() == 1){
1509 String resourceId = "";
1510 for(Resource resource:resourceList){
1511 resourceId = resource.getResourceId();
1513 String homingList = getJsonValue(content, "solutionInfo.placementInfo");
1514 JSONArray placementArr = null;
1516 placementArr = new JSONArray(homingList);
1518 catch (Exception e) {
1521 if(placementArr.length() == 1){
1522 content = content.replace("((SERVICE_RESOURCE_ID))", resourceId);
1524 String licenseInfoList = getJsonValue(content, "solutionInfo.licenseInfo");
1525 JSONArray licenseArr = null;
1527 licenseArr = new JSONArray(licenseInfoList);
1529 catch (Exception e) {
1532 if(licenseArr.length() == 1){
1533 content = content.replace("((SERVICE_RESOURCE_ID))", resourceId);
1538 String homingList = getJsonValue(content, "solutionInfo.placementInfo");
1539 String licenseInfoList = getJsonValue(content, "solutionInfo.licenseInfo");
1540 JSONArray placementArr = new JSONArray(homingList);
1541 JSONArray licenseArr = new JSONArray(licenseInfoList);
1542 for (Resource resource: resourceList) {
1543 String resourceModuleName = resource.getModelInfo().getModelInstanceName();
1544 String resourceId = resource.getResourceId();
1546 for (int i=0; i<placementArr.length(); i++) {
1547 JSONObject placementObj = placementArr.getJSONObject(i);
1548 String placementModuleName = placementObj.getString("resourceModuleName");
1549 if (placementModuleName.equalsIgnoreCase(resourceModuleName)) {
1550 String placementString = placementObj.toString();
1551 placementString = placementString.replace("((SERVICE_RESOURCE_ID))", resourceId);
1552 JSONObject newPlacementObj = new JSONObject(placementString);
1553 placementArr.put(i, newPlacementObj);
1557 for (int i=0; i<licenseArr.length(); i++) {
1558 JSONObject licenseObj = licenseArr.getJSONObject(i);
1559 String licenseModuleName = licenseObj.getString("resourceModuleName");
1560 if (licenseModuleName.equalsIgnoreCase(resourceModuleName)) {
1561 String licenseString = licenseObj.toString();
1562 licenseString = licenseString.replace("((SERVICE_RESOURCE_ID))", resourceId);
1563 JSONObject newLicenseObj = new JSONObject(licenseString);
1564 licenseArr.put(i, newLicenseObj);
1568 String newPlacementInfos = placementArr.toString();
1569 String newLicenseInfos = licenseArr.toString();
1570 content = updJsonValue(content, "solutionInfo.placementInfo", newPlacementInfos);
1571 content = updJsonValue(content, "solutionInfo.licenseInfo", newLicenseInfos);
1573 catch(Exception e) {
1580 msoLogger.debug("Injecting " + messageType + " message");
1582 Response response = workflowMessageResource.deliver(contentType, messageType, correlator, content);
1583 msoLogger.debug("Workflow response to " + messageType + " message: " + response);
1589 * Wait for the process to end.
1590 * @param businessKey the process business key
1591 * @param timeout the amount of time to wait, in milliseconds
1593 protected void waitForProcessEnd(String businessKey, long timeout) {
1594 msoLogger.debug("Waiting " + timeout + "ms for process with business key " +
1595 businessKey + " to end");
1597 long now = System.currentTimeMillis() + timeout;
1598 long endTime = now + timeout;
1600 while (now <= endTime) {
1601 if (isProcessEnded(businessKey)) {
1602 msoLogger.debug("Process with business key " + businessKey + " has ended");
1608 } catch (InterruptedException e) {
1609 String msg = "Interrupted waiting for process with business key " +
1610 businessKey + " to end";
1611 msoLogger.debug(msg);
1615 now = System.currentTimeMillis();
1618 String msg = "Process with business key " + businessKey +
1619 " did not end within " + timeout + "ms";
1620 msoLogger.debug(msg);
1625 * Wait for the process to end. Must be used when multiple process instances exist with
1626 * this same business key such as when its passed to subflows or shared across multiple
1629 * @param businessKey the process business key
1630 * @param processName the process definition name
1631 * @param timeout the amount of time to wait, in milliseconds
1634 protected void waitForProcessEnd(String businessKey, String processName, long timeout) {
1635 msoLogger.debug("Waiting " + timeout + "ms for process with business key " +
1636 businessKey + " to end");
1638 long now = System.currentTimeMillis() + timeout;
1639 long endTime = now + timeout;
1641 while (now <= endTime) {
1642 if (isProcessEnded(businessKey, processName)) {
1643 msoLogger.debug("Process with business key " + businessKey + " has ended");
1649 } catch (InterruptedException e) {
1650 String msg = "Interrupted waiting for process with business key " +
1651 businessKey + " to end";
1652 msoLogger.debug(msg);
1656 now = System.currentTimeMillis();
1659 String msg = "Process with business key " + businessKey +
1660 " did not end within " + timeout + "ms";
1661 msoLogger.debug(msg);
1666 * Verifies that the specified historic process variable has the specified value.
1667 * If the variable does not have the specified value, the test is failed.
1669 * @param businessKey the process business key
1670 * @param variable the variable name
1671 * @param value the expected variable value
1673 protected void checkVariable(String businessKey, String variable, Object value) {
1674 if (!isProcessEnded(businessKey)) {
1675 fail("Cannot get historic variable " + variable + " because process with business key " +
1676 businessKey + " has not ended");
1679 Object variableValue = getVariableFromHistory(businessKey, variable);
1680 assertEquals(value, variableValue);
1684 * Checks to see if the specified process is ended.
1685 * @param businessKey the process business Key
1686 * @return true if the process is ended
1688 protected boolean isProcessEnded(String businessKey) {
1689 HistoricProcessInstance processInstance = historyService
1690 .createHistoricProcessInstanceQuery().processInstanceBusinessKey(businessKey).singleResult();
1691 return processInstance != null && processInstance.getEndTime() != null;
1695 * Checks to see if the specified process is ended.
1697 * @param processInstanceId the process Instance Id
1698 * @return true if the process is ended
1700 protected boolean isProcessEndedByProcessInstanceId(String processInstanceId) {
1701 HistoricProcessInstance processInstance = historyService
1702 .createHistoricProcessInstanceQuery().processInstanceId(processInstanceId).singleResult();
1703 return processInstance != null && processInstance.getEndTime() != null;
1707 * Checks to see if the specified process is ended.
1711 //TODO combine into 1
1712 private boolean isProcessEnded(String businessKey, String processName) {
1713 HistoricProcessInstance processInstance = historyService
1714 .createHistoricProcessInstanceQuery().processInstanceBusinessKey(businessKey).processDefinitionName(processName).singleResult();
1715 return processInstance != null && processInstance.getEndTime() != null;
1719 * Gets a variable value from a historical process instance. The business key must be unique.
1721 * @param businessKey the process business key
1722 * @param variableName the variable name
1723 * @return the variable value or null if the variable does not exist
1725 protected Object getVariableFromHistory(String businessKey, String variableName) {
1727 HistoricProcessInstance processInstance = historyService
1728 .createHistoricProcessInstanceQuery().processInstanceBusinessKey(businessKey).singleResult();
1730 if (processInstance == null) {
1734 HistoricVariableInstance v = historyService
1735 .createHistoricVariableInstanceQuery().processInstanceId(processInstance.getId())
1736 .variableName(variableName).singleResult();
1737 return v == null ? null : v.getValue();
1738 } catch (Exception e) {
1739 msoLogger.debug("Error retrieving variable " + variableName +
1740 " from historical process with business key " + businessKey + ": " + e);
1746 * Gets a variable value from a process instance based on businessKey and process name.
1747 * Must be used when multiple instances exist with the same business key such as when
1748 * business key is passed to subflows or shared across multiple processes. This method
1749 * can obtain variables from mainflows and from subflows.
1751 * @param businessKey the process business key
1752 * @param processName the process definition name
1753 * @param variableName the variable name
1754 * @return the variable value or null if the variable does not exist
1757 protected Object getVariableFromHistory(String businessKey, String processName, String variableName){
1759 HistoricProcessInstance processInstance = historyService.createHistoricProcessInstanceQuery().processInstanceBusinessKey(businessKey).processDefinitionName(processName)
1762 if(processInstance == null){
1765 HistoricVariableInstance variable = historyService.createHistoricVariableInstanceQuery().processInstanceId(processInstance.getId()).variableName(variableName).singleResult();
1767 return variable == null ? null : variable.getValue();
1768 }catch(ProcessEngineException e){
1769 msoLogger.debug("Multiple proccess instances exist with process name " + processName + " and business key " + businessKey + ". Must pass instance index as a parameter.");
1771 }catch(Exception e){
1772 msoLogger.debug("Error retrieving variable " + variableName + " from historical process for process " + processName + " with business key " + businessKey + ": " + e);
1778 * Gets the value of a process variable from x instance of y process. Must be used when
1779 * multiple instances exist with the same business key AND process name. This method
1780 * shall be used primarily for obtaining subflow variables when the business key is
1781 * passed to the subflow AND the subflow is called multiple times in a given flow.
1783 * @param businessKey the process business key
1784 * @param processName the name of the subflow that contains the variable
1785 * @param variableName the variable name
1786 * @param processInstanceIndex the instance in which the subprocess was called
1787 * @return the variable value or null if the variable does not exist
1790 protected Object getVariableFromHistory(String businessKey, int subflowInstanceIndex, String processName, String variableName){
1792 List<HistoricProcessInstance> processInstanceList = historyService.createHistoricProcessInstanceQuery().processInstanceBusinessKey(businessKey).processDefinitionName(processName)
1795 if(processInstanceList == null){
1798 processInstanceList.sort((m1, m2) -> m1.getStartTime().compareTo(m2.getStartTime()));
1800 HistoricProcessInstance processInstance = processInstanceList.get(subflowInstanceIndex);
1801 HistoricVariableInstance variable = historyService.createHistoricVariableInstanceQuery().processInstanceId(processInstance.getId())
1802 .variableName(variableName).singleResult();
1804 return variable == null ? null : variable.getValue();
1805 }catch(Exception e) {
1806 msoLogger.debug("Error retrieving variable " + variableName + " from historical process for process " + processName + " with business key " + businessKey + ": " + e);
1813 * Gets the value of a subflow variable from the specified subflow's
1814 * historical process instance.
1816 * DEPRECATED - Use method getVariableFromHistory(businessKey, processName, variableName) instead
1818 * @param subflowName - the name of the subflow that contains the variable
1819 * @param variableName the variable name
1821 * @return the variable value, or null if the variable could not be obtained
1825 protected Object getVariableFromSubflowHistory(String subflowName, String variableName) {
1827 List<HistoricProcessInstance> processInstanceList = historyService
1828 .createHistoricProcessInstanceQuery().processDefinitionName(subflowName).list();
1830 if (processInstanceList == null) {
1834 processInstanceList.sort((m1, m2) -> m1.getStartTime().compareTo(m2.getStartTime()));
1836 HistoricProcessInstance processInstance = processInstanceList.get(0);
1838 HistoricVariableInstance v = historyService
1839 .createHistoricVariableInstanceQuery().processInstanceId(processInstance.getId())
1840 .variableName(variableName).singleResult();
1841 return v == null ? null : v.getValue();
1842 } catch (Exception e) {
1843 msoLogger.debug("Error retrieving variable " + variableName +
1844 " from sub flow: " + subflowName + ", Exception is: " + e);
1850 * Gets the value of a subflow variable from the subflow's
1851 * historical process x instance.
1853 * DEPRECATED: Use method getVariableFromHistory(businessKey, processInstanceIndex, processName, variableName) instead
1855 * @param subflowName - the name of the subflow that contains the variable
1856 * @param variableName the variable name
1857 * @param subflowInstanceIndex - the instance of the subflow (use when same subflow is called more than once from mainflow)
1859 * @return the variable value, or null if the variable could not be obtained
1862 protected Object getVariableFromSubflowHistory(int subflowInstanceIndex, String subflowName, String variableName) {
1864 List<HistoricProcessInstance> processInstanceList = historyService.createHistoricProcessInstanceQuery().processDefinitionName(subflowName).list();
1866 if (processInstanceList == null) {
1870 processInstanceList.sort((m1, m2) -> m1.getStartTime().compareTo(m2.getStartTime()));
1872 HistoricProcessInstance processInstance = processInstanceList.get(subflowInstanceIndex);
1874 HistoricVariableInstance v = historyService.createHistoricVariableInstanceQuery().processInstanceId(processInstance.getId())
1875 .variableName(variableName).singleResult();
1876 return v == null ? null : v.getValue();
1877 } catch (Exception e) {
1878 msoLogger.debug("Error retrieving variable " + variableName +
1879 " from " + subflowInstanceIndex + " instance index of sub flow: " + subflowName + ", Exception is: " + e);
1885 * Extracts text from an XML element. This method is not namespace aware
1886 * (namespaces are ignored). The first matching element is selected.
1887 * @param xml the XML document or fragment
1888 * @param tag the desired element, e.g. "<name>"
1889 * @return the element text, or null if the element was not found
1891 protected String getXMLTextElement(String xml, String tag) {
1892 xml = removeXMLNamespaces(xml);
1894 if (!tag.startsWith("<")) {
1895 tag = "<" + tag + ">";
1898 int start = xml.indexOf(tag);
1904 int end = xml.indexOf('<', start + tag.length());
1910 return xml.substring(start + tag.length(), end);
1914 * Removes namespace definitions and prefixes from XML, if any.
1916 private String removeXMLNamespaces(String xml) {
1917 // remove xmlns declaration
1918 xml = xml.replaceAll("xmlns.*?(\"|\').*?(\"|\')", "");
1920 // remove opening tag prefix
1921 xml = xml.replaceAll("(<)(\\w+:)(.*?>)", "$1$3");
1923 // remove closing tags prefix
1924 xml = xml.replaceAll("(</)(\\w+:)(.*?>)", "$1$3");
1926 // remove extra spaces left when xmlns declarations are removed
1927 xml = xml.replaceAll("\\s+>", ">");
1933 * Asserts that two XML documents are semantically equivalent. Differences
1934 * in whitespace or in namespace usage do not affect the comparison.
1935 * @param expected the expected XML
1936 * @param actual the XML to test
1937 * @throws SAXException
1938 * @throws IOException
1940 public static void assertXMLEquals(String expected, String actual)
1941 throws SAXException, IOException {
1942 XMLUnit.setIgnoreWhitespace(true);
1943 XMLUnit.setIgnoreAttributeOrder(true);
1944 DetailedDiff diff = new DetailedDiff(XMLUnit.compareXML(expected, actual));
1945 List<?> allDifferences = diff.getAllDifferences();
1946 assertEquals("Differences found: " + diff.toString(), 0, allDifferences.size());
1950 * A test implementation of AsynchronousResponse.
1952 public class TestAsyncResponse {
1953 Response response = null;
1958 public synchronized void setResponse(Response response) {
1959 this.response = response;
1963 * Gets the response.
1964 * @return the response, or null if none has been produced yet
1966 public synchronized Response getResponse() {
1972 * An object that contains callback data for a "program".
1974 public class CallbackSet {
1975 private final Map<String, CallbackData> map = new HashMap<>();
1978 * Add untyped callback data to the set.
1979 * @param action the action with which the data is associated
1980 * @param content the callback data
1982 public void put(String action, String content) {
1983 map.put(action, new CallbackData(null, null, content));
1987 * Add callback data to the set.
1988 * @param action the action with which the data is associated
1989 * @param messageType the callback message type
1990 * @param content the callback data
1992 public void put(String action, String messageType, String content) {
1993 map.put(action, new CallbackData(null, messageType, content));
1997 * Add callback data to the set.
1998 * @param action the action with which the data is associated
1999 * @param contentType the callback HTTP content type
2000 * @param messageType the callback message type
2001 * @param content the callback data
2003 public void put(String action, String contentType, String messageType, String content) {
2004 map.put(action, new CallbackData(contentType, messageType, content));
2008 * Retrieve callback data from the set.
2009 * @param action the action with which the data is associated
2010 * @return the callback data, or null if there is none for the specified operation
2012 public CallbackData get(String action) {
2013 return map.get(action);
2018 * Represents a callback data item.
2020 public class CallbackData {
2021 private final String contentType;
2022 private final String messageType;
2023 private final String content;
2027 * @param contentType the HTTP content type (optional)
2028 * @param messageType the callback message type (optional)
2029 * @param content the content
2031 public CallbackData(String contentType, String messageType, String content) {
2032 this.contentType = contentType;
2033 this.messageType = messageType;
2034 this.content = content;
2038 * Gets the callback HTTP content type, possibly null.
2040 public String getContentType() {
2045 * Gets the callback message type, possibly null.
2047 public String getMessageType() {
2052 * Gets the callback content.
2054 public String getContent() {
2060 * A tool for evaluating XPath expressions.
2062 protected class XPathTool {
2063 private final DocumentBuilderFactory factory;
2064 private final SimpleNamespaceContext context = new SimpleNamespaceContext();
2065 private final XPath xpath = XPathFactory.newInstance().newXPath();
2066 private String xml = null;
2067 private Document doc = null;
2072 public XPathTool() {
2073 factory = DocumentBuilderFactory.newInstance();
2074 factory.setNamespaceAware(true);
2075 xpath.setNamespaceContext(context);
2080 * @param prefix the namespace prefix
2081 * @param uri the namespace uri
2083 public synchronized void addNamespace(String prefix, String uri) {
2084 context.add(prefix, uri);
2088 * Sets the XML content to be operated on.
2089 * @param xml the XML content
2091 public synchronized void setXML(String xml) {
2097 * Returns the document object.
2098 * @return the document object, or null if XML has not been set
2099 * @throws SAXException
2100 * @throws IOException
2101 * @throws ParserConfigurationException
2103 public synchronized Document getDocument()
2104 throws ParserConfigurationException, IOException, SAXException {
2114 * Evaluates the specified XPath expression and returns a string result.
2115 * This method throws exceptions on error.
2116 * @param expression the expression
2117 * @return the result object
2118 * @throws ParserConfigurationException
2119 * @throws IOException
2120 * @throws SAXException
2121 * @throws XPathExpressionException on error
2123 public synchronized String evaluate(String expression)
2124 throws ParserConfigurationException, SAXException,
2125 IOException, XPathExpressionException {
2126 return (String) evaluate(expression, XPathConstants.STRING);
2130 * Evaluates the specified XPath expression.
2131 * This method throws exceptions on error.
2132 * @param expression the expression
2133 * @param returnType the return type
2134 * @return the result object
2135 * @throws ParserConfigurationException
2136 * @throws IOException
2137 * @throws SAXException
2138 * @throws XPathExpressionException on error
2140 public synchronized Object evaluate(String expression, QName returnType)
2141 throws ParserConfigurationException, SAXException,
2142 IOException, XPathExpressionException {
2145 XPathExpression expr = xpath.compile(expression);
2146 return expr.evaluate(doc, returnType);
2150 * Private helper method that builds the document object.
2151 * Assumes the calling method is synchronized.
2152 * @throws ParserConfigurationException
2153 * @throws IOException
2154 * @throws SAXException
2156 private void buildDocument() throws ParserConfigurationException,
2157 IOException, SAXException {
2160 throw new IOException("XML input is null");
2163 DocumentBuilder builder = factory.newDocumentBuilder();
2164 InputSource source = new InputSource(new StringReader(xml));
2165 doc = builder.parse(source);
2171 * A NamespaceContext class based on a Map.
2173 private class SimpleNamespaceContext implements NamespaceContext {
2174 private Map<String, String> prefixMap = new HashMap<>();
2175 private Map<String, String> uriMap = new HashMap<>();
2177 public synchronized void add(String prefix, String uri) {
2178 prefixMap.put(prefix, uri);
2179 uriMap.put(uri, prefix);
2183 public synchronized String getNamespaceURI(String prefix) {
2184 return prefixMap.get(prefix);
2188 public Iterator<String> getPrefixes(String uri) {
2189 List<String> list = new ArrayList<>();
2190 String prefix = uriMap.get(uri);
2191 if (prefix != null) {
2194 return list.iterator();
2198 public String getPrefix(String uri) {
2199 return uriMap.get(uri);
2204 * A VnfNotify XPathTool.
2206 protected class VnfNotifyXPathTool extends XPathTool {
2207 public VnfNotifyXPathTool() {
2208 addNamespace("tns", "http://org.onap.so/vnfNotify");
2213 * Helper class to make it easier to create this type.
2215 private static class CreateVnfNotificationOutputs
2216 extends CreateVnfNotification.Outputs {
2217 public void add(String key, String value) {
2218 Entry entry = new Entry();
2220 entry.setValue(value);
2221 getEntry().add(entry);
2226 * Helper class to make it easier to create this type.
2228 private static class UpdateVnfNotificationOutputs
2229 extends UpdateVnfNotification.Outputs {
2230 public void add(String key, String value) {
2231 Entry entry = new Entry();
2233 entry.setValue(value);
2234 getEntry().add(entry);