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) {
935 content = content.replace("((REQUEST-ID))", sdncRequestId);
936 // Deprecated usage. All test code should switch to the (( ... )) syntax.
937 content = content.replace("{{REQUEST-ID}}", sdncRequestId);
939 msoLogger.debug("Injecting SDNC adapter callback");
941 Response response = workflowMessageResource.deliver(contentType, "SDNCAResponse", sdncRequestId, content);
942 msoLogger.debug("Workflow response to SDNC adapter callback: " + response);
947 * Injects a single SDNC adapter callback request. The specified callback data
948 * may contain the placeholder string ((REQUEST-ID)) which is replaced with
949 * the actual SDNC request ID. Note: this is not the requestId in the original
951 * @param content the content of the callback
952 * @param respCode the response code (normally 200)
953 * @param respMsg the response message (normally "OK")
954 * @param timeout the timeout in milliseconds
955 * @return true if the callback could be injected, false otherwise
957 protected boolean injectSDNCCallback(int respCode, String respMsg,
958 String content, long timeout) {
960 String sdncRequestId = (String) getProcessVariable("sdncAdapter",
961 "SDNCA_requestId", timeout);
963 if (sdncRequestId == null) {
967 content = content.replace("((REQUEST-ID))", sdncRequestId);
968 // Deprecated usage. All test code should switch to the (( ... )) syntax.
969 content = content.replace("{{REQUEST-ID}}", sdncRequestId);
971 // TODO this needs to be fixed. It is causing double tags and content
972 // Need to parse content before setting below since content includes not just RequestData or modify callback files to only contain RequestData contents.
974 msoLogger.debug("Injecting SDNC adapter callback");
975 CallbackHeader callbackHeader = new CallbackHeader();
976 callbackHeader.setRequestId(sdncRequestId);
977 callbackHeader.setResponseCode(String.valueOf(respCode));
978 callbackHeader.setResponseMessage(respMsg);
979 SDNCAdapterCallbackRequest sdncAdapterCallbackRequest = new SDNCAdapterCallbackRequest();
980 sdncAdapterCallbackRequest.setCallbackHeader(callbackHeader);
981 sdncAdapterCallbackRequest.setRequestData(content);
982 SDNCAdapterResponse sdncAdapterResponse = callbackService.sdncAdapterCallback(sdncAdapterCallbackRequest);
983 msoLogger.debug("Workflow response to SDNC adapter callback: " + sdncAdapterResponse);
989 * Injects a single VNF adapter callback request. The specified callback data
990 * may contain the placeholder string ((MESSAGE-ID)) which is replaced with
991 * the actual message ID. Note: this is not the requestId in the original
993 * @param contentType the HTTP content type for the callback
994 * @param content the content of the callback
995 * @param timeout the timeout in milliseconds
996 * @return true if the callback could be injected, false otherwise
998 protected boolean injectVnfAdapterRestCallback(String contentType, String content, long timeout) {
999 String messageId = (String) getProcessVariable("vnfAdapterRestV1",
1000 "VNFAResponse_CORRELATOR", timeout);
1002 if (messageId == null) {
1006 content = content.replace("((MESSAGE-ID))", messageId);
1007 // Deprecated usage. All test code should switch to the (( ... )) syntax.
1008 content = content.replace("{{MESSAGE-ID}}", messageId);
1010 msoLogger.debug("Injecting VNF adapter callback");
1012 Response response = workflowMessageResource.deliver(contentType, "VNFAResponse", messageId, content);
1013 msoLogger.debug("Workflow response to VNF adapter callback: " + response);
1018 * Injects a Create VNF adapter callback request. The specified callback data
1019 * may contain the placeholder string ((MESSAGE-ID)) which is replaced with
1020 * the actual message ID. It may also contain the placeholder string
1021 * ((REQUEST-ID)) which is replaced request ID of the original MSO request.
1022 * @param content the content of the callback
1023 * @param timeout the timeout in milliseconds
1024 * @return true if the callback could be injected, false otherwise
1025 * @throws JAXBException if the content does not adhere to the schema
1027 protected boolean injectCreateVNFCallback(String content, long timeout) {
1029 String messageId = (String) getProcessVariable("vnfAdapterCreateV1",
1030 "VNFC_messageId", timeout);
1032 if (messageId == null) {
1036 content = content.replace("((MESSAGE-ID))", messageId);
1037 // Deprecated usage. All test code should switch to the (( ... )) syntax.
1038 content = content.replace("{{MESSAGE-ID}}", messageId);
1040 if(content.contains("((REQUEST-ID))")){
1041 content = content.replace("((REQUEST-ID))", msoRequestId);
1042 // Deprecated usage. All test code should switch to the (( ... )) syntax.
1043 content = content.replace("{{REQUEST-ID}}", msoRequestId);
1046 msoLogger.debug("Injecting VNF adapter callback");
1048 // Is it possible to unmarshal this with JAXB? I couldn't.
1050 CreateVnfNotification createVnfNotification = new CreateVnfNotification();
1051 XPathTool xpathTool = new VnfNotifyXPathTool();
1052 xpathTool.setXML(content);
1055 String completed = xpathTool.evaluate(
1056 "/tns:createVnfNotification/tns:completed/text()");
1057 createVnfNotification.setCompleted("true".equals(completed));
1059 String vnfId = xpathTool.evaluate(
1060 "/tns:createVnfNotification/tns:vnfId/text()");
1061 createVnfNotification.setVnfId(vnfId);
1063 NodeList entries = (NodeList) xpathTool.evaluate(
1064 "/tns:createVnfNotification/tns:outputs/tns:entry",
1065 XPathConstants.NODESET);
1067 CreateVnfNotificationOutputs outputs = new CreateVnfNotificationOutputs();
1069 for (int i = 0; i < entries.getLength(); i++) {
1070 Node node = entries.item(i);
1072 if (node.getNodeType() == Node.ELEMENT_NODE) {
1073 Element entry = (Element) node;
1074 String key = entry.getElementsByTagNameNS("*", "key").item(0).getTextContent();
1075 String value = entry.getElementsByTagNameNS("*", "value").item(0).getTextContent();
1076 outputs.add(key, value);
1080 createVnfNotification.setOutputs(outputs);
1082 VnfRollback rollback = new VnfRollback();
1084 String cloudSiteId = xpathTool.evaluate(
1085 "/tns:createVnfNotification/tns:rollback/tns:cloudSiteId/text()");
1086 rollback.setCloudSiteId(cloudSiteId);
1088 String requestId = xpathTool.evaluate(
1089 "/tns:createVnfNotification/tns:rollback/tns:msoRequest/tns:requestId/text()");
1090 String serviceInstanceId = xpathTool.evaluate(
1091 "/tns:createVnfNotification/tns:rollback/tns:msoRequest/tns:serviceInstanceId/text()");
1093 if (requestId != null || serviceInstanceId != null) {
1094 MsoRequest msoRequest = new MsoRequest();
1095 msoRequest.setRequestId(requestId);
1096 msoRequest.setServiceInstanceId(serviceInstanceId);
1097 rollback.setMsoRequest(msoRequest);
1100 String tenantCreated = xpathTool.evaluate(
1101 "/tns:createVnfNotification/tns:rollback/tns:tenantCreated/text()");
1102 rollback.setTenantCreated("true".equals(tenantCreated));
1104 String tenantId = xpathTool.evaluate(
1105 "/tns:createVnfNotification/tns:rollback/tns:tenantId/text()");
1106 rollback.setTenantId(tenantId);
1108 String vnfCreated = xpathTool.evaluate(
1109 "/tns:createVnfNotification/tns:rollback/tns:vnfCreated/text()");
1110 rollback.setVnfCreated("true".equals(vnfCreated));
1112 String rollbackVnfId = xpathTool.evaluate(
1113 "/tns:createVnfNotification/tns:rollback/tns:vnfId/text()");
1114 rollback.setVnfId(rollbackVnfId);
1116 createVnfNotification.setRollback(rollback);
1118 } catch (Exception e) {
1119 msoLogger.debug("Failed to unmarshal VNF callback content:");
1120 msoLogger.debug(content);
1124 VnfAdapterNotifyServiceImpl notifyService = new VnfAdapterNotifyServiceImpl();
1127 notifyService.createVnfNotification(
1129 createVnfNotification.isCompleted(),
1130 createVnfNotification.getException(),
1131 createVnfNotification.getErrorMessage(),
1132 createVnfNotification.getVnfId(),
1133 createVnfNotification.getOutputs(),
1134 createVnfNotification.getRollback());
1140 * Injects a Delete VNF adapter callback request. The specified callback data
1141 * may contain the placeholder string ((MESSAGE-ID)) which is replaced with
1142 * the actual message ID. It may also contain the placeholder string
1143 * ((REQUEST-ID)) which is replaced request ID of the original MSO request.
1144 * @param content the content of the callback
1145 * @param timeout the timeout in milliseconds
1146 * @return true if the callback could be injected, false otherwise
1147 * @throws JAXBException if the content does not adhere to the schema
1149 protected boolean injectDeleteVNFCallback(String content, long timeout) {
1151 String messageId = (String) getProcessVariable("vnfAdapterDeleteV1",
1152 "VNFDEL_uuid", timeout);
1154 if (messageId == null) {
1158 content = content.replace("((MESSAGE-ID))", messageId);
1159 // Deprecated usage. All test code should switch to the (( ... )) syntax.
1160 content = content.replace("{{MESSAGE-ID}}", messageId);
1162 msoLogger.debug("Injecting VNF adapter delete callback");
1164 // Is it possible to unmarshal this with JAXB? I couldn't.
1166 DeleteVnfNotification deleteVnfNotification = new DeleteVnfNotification();
1167 XPathTool xpathTool = new VnfNotifyXPathTool();
1168 xpathTool.setXML(content);
1171 String completed = xpathTool.evaluate(
1172 "/tns:deleteVnfNotification/tns:completed/text()");
1173 deleteVnfNotification.setCompleted("true".equals(completed));
1174 // if notification failure, set the exception and error message
1175 if (deleteVnfNotification.isCompleted() == false) {
1176 deleteVnfNotification.setException(MsoExceptionCategory.INTERNAL);
1177 deleteVnfNotification.setErrorMessage(xpathTool.evaluate(
1178 "/tns:deleteVnfNotification/tns:errorMessage/text()")) ;
1181 } catch (Exception e) {
1182 msoLogger.debug("Failed to unmarshal VNF Delete callback content:");
1183 msoLogger.debug(content);
1187 VnfAdapterNotifyServiceImpl notifyService = new VnfAdapterNotifyServiceImpl();
1190 notifyService.deleteVnfNotification(
1192 deleteVnfNotification.isCompleted(),
1193 deleteVnfNotification.getException(),
1194 deleteVnfNotification.getErrorMessage());
1200 * Injects a Update VNF adapter callback request. The specified callback data
1201 * may contain the placeholder string ((MESSAGE-ID)) which is replaced with
1202 * the actual message ID. It may also contain the placeholder string
1203 * ((REQUEST-ID)) which is replaced request ID of the original MSO request.
1204 * @param content the content of the callback
1205 * @param timeout the timeout in milliseconds
1206 * @return true if the callback could be injected, false otherwise
1207 * @throws JAXBException if the content does not adhere to the schema
1209 protected boolean injectUpdateVNFCallback(String content, long timeout) {
1211 String messageId = (String) getProcessVariable("vnfAdapterUpdate",
1212 "VNFU_messageId", timeout);
1214 if (messageId == null) {
1218 content = content.replace("((MESSAGE-ID))", messageId);
1219 // Deprecated usage. All test code should switch to the (( ... )) syntax.
1220 content = content.replace("{{MESSAGE-ID}}", messageId);
1222 content = content.replace("((REQUEST-ID))", msoRequestId);
1223 // Deprecated usage. All test code should switch to the (( ... )) syntax.
1224 content = content.replace("{{REQUEST-ID}}", msoRequestId);
1226 msoLogger.debug("Injecting VNF adapter callback");
1228 // Is it possible to unmarshal this with JAXB? I couldn't.
1230 UpdateVnfNotification updateVnfNotification = new UpdateVnfNotification();
1231 XPathTool xpathTool = new VnfNotifyXPathTool();
1232 xpathTool.setXML(content);
1235 String completed = xpathTool.evaluate(
1236 "/tns:updateVnfNotification/tns:completed/text()");
1237 updateVnfNotification.setCompleted("true".equals(completed));
1239 NodeList entries = (NodeList) xpathTool.evaluate(
1240 "/tns:updateVnfNotification/tns:outputs/tns:entry",
1241 XPathConstants.NODESET);
1243 UpdateVnfNotificationOutputs outputs = new UpdateVnfNotificationOutputs();
1245 for (int i = 0; i < entries.getLength(); i++) {
1246 Node node = entries.item(i);
1248 if (node.getNodeType() == Node.ELEMENT_NODE) {
1249 Element entry = (Element) node;
1250 String key = entry.getElementsByTagNameNS("*", "key").item(0).getTextContent();
1251 String value = entry.getElementsByTagNameNS("*", "value").item(0).getTextContent();
1252 outputs.add(key, value);
1256 updateVnfNotification.setOutputs(outputs);
1258 VnfRollback rollback = new VnfRollback();
1260 String cloudSiteId = xpathTool.evaluate(
1261 "/tns:updateVnfNotification/tns:rollback/tns:cloudSiteId/text()");
1262 rollback.setCloudSiteId(cloudSiteId);
1264 String requestId = xpathTool.evaluate(
1265 "/tns:updateVnfNotification/tns:rollback/tns:msoRequest/tns:requestId/text()");
1266 String serviceInstanceId = xpathTool.evaluate(
1267 "/tns:updateVnfNotification/tns:rollback/tns:msoRequest/tns:serviceInstanceId/text()");
1269 if (requestId != null || serviceInstanceId != null) {
1270 MsoRequest msoRequest = new MsoRequest();
1271 msoRequest.setRequestId(requestId);
1272 msoRequest.setServiceInstanceId(serviceInstanceId);
1273 rollback.setMsoRequest(msoRequest);
1276 String tenantCreated = xpathTool.evaluate(
1277 "/tns:updateVnfNotification/tns:rollback/tns:tenantCreated/text()");
1278 rollback.setTenantCreated("true".equals(tenantCreated));
1280 String tenantId = xpathTool.evaluate(
1281 "/tns:updateVnfNotification/tns:rollback/tns:tenantId/text()");
1282 rollback.setTenantId(tenantId);
1284 String vnfCreated = xpathTool.evaluate(
1285 "/tns:updateVnfNotification/tns:rollback/tns:vnfCreated/text()");
1286 rollback.setVnfCreated("true".equals(vnfCreated));
1288 String rollbackVnfId = xpathTool.evaluate(
1289 "/tns:updateVnfNotification/tns:rollback/tns:vnfId/text()");
1290 rollback.setVnfId(rollbackVnfId);
1292 updateVnfNotification.setRollback(rollback);
1294 } catch (Exception e) {
1295 msoLogger.debug("Failed to unmarshal VNF callback content:");
1296 msoLogger.debug(content);
1300 VnfAdapterNotifyServiceImpl notifyService = new VnfAdapterNotifyServiceImpl();
1303 notifyService.updateVnfNotification(
1305 updateVnfNotification.isCompleted(),
1306 updateVnfNotification.getException(),
1307 updateVnfNotification.getErrorMessage(),
1308 updateVnfNotification.getOutputs(),
1309 updateVnfNotification.getRollback());
1315 * Runs a program to inject workflow messages into the test environment.
1316 * A program is essentially just a list of keys that identify event data
1317 * to be injected, in sequence. An example program:
1321 * Errors are handled with junit assertions and will cause the test to fail.
1322 * NOTE: Each callback must have a workflow message type associated with it.
1323 * @param callbacks an object containing event data for the program
1324 * @param program the program to execute
1326 protected void injectWorkflowMessages(CallbackSet callbacks, String program) {
1328 String[] cmds = program.replaceAll("\\s+", "").split(",");
1330 for (String cmd : cmds) {
1331 String action = cmd;
1332 String modifier = "STD";
1334 if (cmd.contains(":")) {
1335 String[] parts = cmd.split(":");
1337 modifier = parts[1];
1340 String messageType = null;
1341 String content = null;
1342 String contentType = null;
1344 if ("STD".equals(modifier)) {
1345 CallbackData callbackData = callbacks.get(action);
1347 if (callbackData == null) {
1348 String msg = "No '" + action + "' workflow message callback is defined";
1349 msoLogger.debug(msg);
1353 messageType = callbackData.getMessageType();
1355 if (messageType == null || messageType.trim().equals("")) {
1356 String msg = "No workflow message type is defined in the '" + action + "' callback";
1357 msoLogger.debug(msg);
1361 content = callbackData.getContent();
1362 contentType = callbackData.getContentType();
1364 String msg = "Invalid workflow message program modifier: '" + modifier + "'";
1365 msoLogger.debug(msg);
1369 if (!injectWorkflowMessage(contentType, messageType, content, 10000)) {
1370 fail("Failed to inject '" + action + "' workflow message");
1375 } catch (InterruptedException e) {
1376 fail("Interrupted after injection of '" + action + "' workflow message");
1382 * Injects a workflow message. The specified callback data may contain the
1383 * placeholder string ((CORRELATOR)) which is replaced with the actual
1385 * @param contentType the HTTP contentType for the message (possibly null)
1386 * @param messageType the message type
1387 * @param content the message content (possibly null)
1388 * @param timeout the timeout in milliseconds
1389 * @return true if the message could be injected, false otherwise
1391 protected boolean injectWorkflowMessage(String contentType, String messageType, String content, long timeout) {
1392 String correlator = (String) getProcessVariable("ReceiveWorkflowMessage",
1393 messageType + "_CORRELATOR", timeout);
1395 if (correlator == null) {
1399 if (content != null) {
1400 content = content.replace("((CORRELATOR))", correlator);
1403 msoLogger.debug("Injecting " + messageType + " message");
1405 Response response = workflowMessageResource.deliver(contentType, messageType, correlator, content);
1406 msoLogger.debug("Workflow response to " + messageType + " message: " + response);
1411 * Runs a program to inject sniro workflow messages into the test environment.
1412 * A program is essentially just a list of keys that identify event data
1413 * to be injected, in sequence. For more details, see
1414 * injectSNIROCallbacks(String contentType, String messageType, String content, long timeout)
1416 * Errors are handled with junit assertions and will cause the test to fail.
1417 * NOTE: Each callback must have a workflow message type associated with it.
1419 * @param callbacks an object containing event data for the program
1420 * @param program the program to execute
1422 protected void injectSNIROCallbacks(CallbackSet callbacks, String program) {
1424 String[] cmds = program.replaceAll("\\s+", "").split(",");
1426 for (String cmd : cmds) {
1427 String action = cmd;
1428 String modifier = "STD";
1430 if (cmd.contains(":")) {
1431 String[] parts = cmd.split(":");
1433 modifier = parts[1];
1436 String messageType = null;
1437 String content = null;
1438 String contentType = null;
1440 if ("STD".equals(modifier)) {
1441 CallbackData callbackData = callbacks.get(action);
1443 if (callbackData == null) {
1444 String msg = "No '" + action + "' workflow message callback is defined";
1445 msoLogger.debug(msg);
1449 messageType = callbackData.getMessageType();
1451 if (messageType == null || messageType.trim().equals("")) {
1452 String msg = "No workflow message type is defined in the '" + action + "' callback";
1453 msoLogger.debug(msg);
1457 content = callbackData.getContent();
1458 contentType = callbackData.getContentType();
1460 String msg = "Invalid workflow message program modifier: '" + modifier + "'";
1461 msoLogger.debug(msg);
1465 if (!injectSNIROCallbacks(contentType, messageType, content, 10000)) {
1466 fail("Failed to inject '" + action + "' workflow message");
1471 } catch (InterruptedException e) {
1472 fail("Interrupted after injection of '" + action + "' workflow message");
1478 * Injects a sniro workflow message. The specified callback response may
1479 * contain the placeholder strings ((CORRELATOR)) and ((SERVICE_RESOURCE_ID))
1480 * The ((CORRELATOR)) is replaced with the actual correlator value from the
1481 * request. The ((SERVICE_RESOURCE_ID)) is replaced with the actual serviceResourceId
1482 * value from the sniro request. Currently this only works with sniro request
1483 * that contain only 1 resource.
1485 * @param contentType the HTTP contentType for the message (possibly null)
1486 * @param messageType the message type
1487 * @param content the message content (possibly null)
1488 * @param timeout the timeout in milliseconds
1489 * @return true if the message could be injected, false otherwise
1491 protected boolean injectSNIROCallbacks(String contentType, String messageType, String content, long timeout) {
1492 String correlator = (String) getProcessVariable("ReceiveWorkflowMessage",
1493 messageType + "_CORRELATOR", timeout);
1495 if (correlator == null) {
1498 if (content != null) {
1499 content = content.replace("((CORRELATOR))", correlator);
1500 if(messageType.equalsIgnoreCase("SNIROResponse")){
1501 ServiceDecomposition decomp = (ServiceDecomposition) getProcessVariable("Homing", "serviceDecomposition", timeout);
1502 List<Resource> resourceList = decomp.getServiceResources();
1503 if(resourceList.size() == 1){
1504 String resourceId = "";
1505 for(Resource resource:resourceList){
1506 resourceId = resource.getResourceId();
1508 String homingList = getJsonValue(content, "solutionInfo.placementInfo");
1509 JSONArray placementArr = null;
1511 placementArr = new JSONArray(homingList);
1513 catch (Exception e) {
1516 if(placementArr.length() == 1){
1517 content = content.replace("((SERVICE_RESOURCE_ID))", resourceId);
1519 String licenseInfoList = getJsonValue(content, "solutionInfo.licenseInfo");
1520 JSONArray licenseArr = null;
1522 licenseArr = new JSONArray(licenseInfoList);
1524 catch (Exception e) {
1527 if(licenseArr.length() == 1){
1528 content = content.replace("((SERVICE_RESOURCE_ID))", resourceId);
1533 String homingList = getJsonValue(content, "solutionInfo.placementInfo");
1534 String licenseInfoList = getJsonValue(content, "solutionInfo.licenseInfo");
1535 JSONArray placementArr = new JSONArray(homingList);
1536 JSONArray licenseArr = new JSONArray(licenseInfoList);
1537 for (Resource resource: resourceList) {
1538 String resourceModuleName = resource.getModelInfo().getModelInstanceName();
1539 String resourceId = resource.getResourceId();
1541 for (int i=0; i<placementArr.length(); i++) {
1542 JSONObject placementObj = placementArr.getJSONObject(i);
1543 String placementModuleName = placementObj.getString("resourceModuleName");
1544 if (placementModuleName.equalsIgnoreCase(resourceModuleName)) {
1545 String placementString = placementObj.toString();
1546 placementString = placementString.replace("((SERVICE_RESOURCE_ID))", resourceId);
1547 JSONObject newPlacementObj = new JSONObject(placementString);
1548 placementArr.put(i, newPlacementObj);
1552 for (int i=0; i<licenseArr.length(); i++) {
1553 JSONObject licenseObj = licenseArr.getJSONObject(i);
1554 String licenseModuleName = licenseObj.getString("resourceModuleName");
1555 if (licenseModuleName.equalsIgnoreCase(resourceModuleName)) {
1556 String licenseString = licenseObj.toString();
1557 licenseString = licenseString.replace("((SERVICE_RESOURCE_ID))", resourceId);
1558 JSONObject newLicenseObj = new JSONObject(licenseString);
1559 licenseArr.put(i, newLicenseObj);
1563 String newPlacementInfos = placementArr.toString();
1564 String newLicenseInfos = licenseArr.toString();
1565 content = updJsonValue(content, "solutionInfo.placementInfo", newPlacementInfos);
1566 content = updJsonValue(content, "solutionInfo.licenseInfo", newLicenseInfos);
1568 catch(Exception e) {
1575 msoLogger.debug("Injecting " + messageType + " message");
1577 Response response = workflowMessageResource.deliver(contentType, messageType, correlator, content);
1578 msoLogger.debug("Workflow response to " + messageType + " message: " + response);
1584 * Wait for the process to end.
1585 * @param businessKey the process business key
1586 * @param timeout the amount of time to wait, in milliseconds
1588 protected void waitForProcessEnd(String businessKey, long timeout) {
1589 msoLogger.debug("Waiting " + timeout + "ms for process with business key " +
1590 businessKey + " to end");
1592 long now = System.currentTimeMillis() + timeout;
1593 long endTime = now + timeout;
1595 while (now <= endTime) {
1596 if (isProcessEnded(businessKey)) {
1597 msoLogger.debug("Process with business key " + businessKey + " has ended");
1603 } catch (InterruptedException e) {
1604 String msg = "Interrupted waiting for process with business key " +
1605 businessKey + " to end";
1606 msoLogger.debug(msg);
1610 now = System.currentTimeMillis();
1613 String msg = "Process with business key " + businessKey +
1614 " did not end within " + timeout + "ms";
1615 msoLogger.debug(msg);
1620 * Wait for the process to end. Must be used when multiple process instances exist with
1621 * this same business key such as when its passed to subflows or shared across multiple
1624 * @param businessKey the process business key
1625 * @param processName the process definition name
1626 * @param timeout the amount of time to wait, in milliseconds
1629 protected void waitForProcessEnd(String businessKey, String processName, long timeout) {
1630 msoLogger.debug("Waiting " + timeout + "ms for process with business key " +
1631 businessKey + " to end");
1633 long now = System.currentTimeMillis() + timeout;
1634 long endTime = now + timeout;
1636 while (now <= endTime) {
1637 if (isProcessEnded(businessKey, processName)) {
1638 msoLogger.debug("Process with business key " + businessKey + " has ended");
1644 } catch (InterruptedException e) {
1645 String msg = "Interrupted waiting for process with business key " +
1646 businessKey + " to end";
1647 msoLogger.debug(msg);
1651 now = System.currentTimeMillis();
1654 String msg = "Process with business key " + businessKey +
1655 " did not end within " + timeout + "ms";
1656 msoLogger.debug(msg);
1661 * Verifies that the specified historic process variable has the specified value.
1662 * If the variable does not have the specified value, the test is failed.
1664 * @param businessKey the process business key
1665 * @param variable the variable name
1666 * @param value the expected variable value
1668 protected void checkVariable(String businessKey, String variable, Object value) {
1669 if (!isProcessEnded(businessKey)) {
1670 fail("Cannot get historic variable " + variable + " because process with business key " +
1671 businessKey + " has not ended");
1674 Object variableValue = getVariableFromHistory(businessKey, variable);
1675 assertEquals(value, variableValue);
1679 * Checks to see if the specified process is ended.
1680 * @param businessKey the process business Key
1681 * @return true if the process is ended
1683 protected boolean isProcessEnded(String businessKey) {
1684 HistoricProcessInstance processInstance = historyService
1685 .createHistoricProcessInstanceQuery().processInstanceBusinessKey(businessKey).singleResult();
1686 return processInstance != null && processInstance.getEndTime() != null;
1690 * Checks to see if the specified process is ended.
1691 <<<<<<< HEAD:bpmn/mso-infrastructure-bpmn/src/test/java/org/onap/so/bpmn/common/WorkflowTest.java
1692 * @param processInstanceId the process Instance Id
1693 * @return true if the process is ended
1695 protected boolean isProcessEndedByProcessInstanceId(String processInstanceId) {
1696 HistoricProcessInstance processInstance = historyService
1697 .createHistoricProcessInstanceQuery().processInstanceId(processInstanceId).singleResult();
1698 return processInstance != null && processInstance.getEndTime() != null;
1702 * Checks to see if the specified process is ended.
1704 >>>>>>> origin/release/1806.51:bpmn/MSOCommonBPMN/src/test/java/org/openecomp/mso/bpmn/common/WorkflowTest.java
1707 //TODO combine into 1
1708 private boolean isProcessEnded(String businessKey, String processName) {
1709 HistoricProcessInstance processInstance = historyService
1710 .createHistoricProcessInstanceQuery().processInstanceBusinessKey(businessKey).processDefinitionName(processName).singleResult();
1711 return processInstance != null && processInstance.getEndTime() != null;
1715 * Gets a variable value from a historical process instance. The business key must be unique.
1717 * @param businessKey the process business key
1718 * @param variableName the variable name
1719 * @return the variable value or null if the variable does not exist
1721 protected Object getVariableFromHistory(String businessKey, String variableName) {
1723 HistoricProcessInstance processInstance = historyService
1724 .createHistoricProcessInstanceQuery().processInstanceBusinessKey(businessKey).singleResult();
1726 if (processInstance == null) {
1730 HistoricVariableInstance v = historyService
1731 .createHistoricVariableInstanceQuery().processInstanceId(processInstance.getId())
1732 .variableName(variableName).singleResult();
1733 return v == null ? null : v.getValue();
1734 } catch (Exception e) {
1735 msoLogger.debug("Error retrieving variable " + variableName +
1736 " from historical process with business key " + businessKey + ": " + e);
1742 * Gets a variable value from a process instance based on businessKey and process name.
1743 * Must be used when multiple instances exist with the same business key such as when
1744 * business key is passed to subflows or shared across multiple processes. This method
1745 * can obtain variables from mainflows and from subflows.
1747 * @param businessKey the process business key
1748 * @param processName the process definition name
1749 * @param variableName the variable name
1750 * @return the variable value or null if the variable does not exist
1753 protected Object getVariableFromHistory(String businessKey, String processName, String variableName){
1755 HistoricProcessInstance processInstance = historyService.createHistoricProcessInstanceQuery().processInstanceBusinessKey(businessKey).processDefinitionName(processName)
1758 if(processInstance == null){
1761 HistoricVariableInstance variable = historyService.createHistoricVariableInstanceQuery().processInstanceId(processInstance.getId()).variableName(variableName).singleResult();
1763 return variable == null ? null : variable.getValue();
1764 }catch(ProcessEngineException e){
1765 msoLogger.debug("Multiple proccess instances exist with process name " + processName + " and business key " + businessKey + ". Must pass instance index as a parameter.");
1767 }catch(Exception e){
1768 msoLogger.debug("Error retrieving variable " + variableName + " from historical process for process " + processName + " with business key " + businessKey + ": " + e);
1774 * Gets the value of a process variable from x instance of y process. Must be used when
1775 * multiple instances exist with the same business key AND process name. This method
1776 * shall be used primarily for obtaining subflow variables when the business key is
1777 * passed to the subflow AND the subflow is called multiple times in a given flow.
1779 * @param businessKey the process business key
1780 * @param processName the name of the subflow that contains the variable
1781 * @param variableName the variable name
1782 * @param processInstanceIndex the instance in which the subprocess was called
1783 * @return the variable value or null if the variable does not exist
1786 protected Object getVariableFromHistory(String businessKey, int subflowInstanceIndex, String processName, String variableName){
1788 List<HistoricProcessInstance> processInstanceList = historyService.createHistoricProcessInstanceQuery().processInstanceBusinessKey(businessKey).processDefinitionName(processName)
1791 if(processInstanceList == null){
1794 processInstanceList.sort((m1, m2) -> m1.getStartTime().compareTo(m2.getStartTime()));
1796 HistoricProcessInstance processInstance = processInstanceList.get(subflowInstanceIndex);
1797 HistoricVariableInstance variable = historyService.createHistoricVariableInstanceQuery().processInstanceId(processInstance.getId())
1798 .variableName(variableName).singleResult();
1800 return variable == null ? null : variable.getValue();
1801 }catch(Exception e) {
1802 msoLogger.debug("Error retrieving variable " + variableName + " from historical process for process " + processName + " with business key " + businessKey + ": " + e);
1809 * Gets the value of a subflow variable from the specified subflow's
1810 * historical process instance.
1812 * DEPRECATED - Use method getVariableFromHistory(businessKey, processName, variableName) instead
1814 * @param subflowName - the name of the subflow that contains the variable
1815 * @param variableName the variable name
1817 * @return the variable value, or null if the variable could not be obtained
1821 protected Object getVariableFromSubflowHistory(String subflowName, String variableName) {
1823 List<HistoricProcessInstance> processInstanceList = historyService
1824 .createHistoricProcessInstanceQuery().processDefinitionName(subflowName).list();
1826 if (processInstanceList == null) {
1830 processInstanceList.sort((m1, m2) -> m1.getStartTime().compareTo(m2.getStartTime()));
1832 HistoricProcessInstance processInstance = processInstanceList.get(0);
1834 HistoricVariableInstance v = historyService
1835 .createHistoricVariableInstanceQuery().processInstanceId(processInstance.getId())
1836 .variableName(variableName).singleResult();
1837 return v == null ? null : v.getValue();
1838 } catch (Exception e) {
1839 msoLogger.debug("Error retrieving variable " + variableName +
1840 " from sub flow: " + subflowName + ", Exception is: " + e);
1846 * Gets the value of a subflow variable from the subflow's
1847 * historical process x instance.
1849 * DEPRECATED: Use method getVariableFromHistory(businessKey, processInstanceIndex, processName, variableName) instead
1851 * @param subflowName - the name of the subflow that contains the variable
1852 * @param variableName the variable name
1853 * @param subflowInstanceIndex - the instance of the subflow (use when same subflow is called more than once from mainflow)
1855 * @return the variable value, or null if the variable could not be obtained
1858 protected Object getVariableFromSubflowHistory(int subflowInstanceIndex, String subflowName, String variableName) {
1860 List<HistoricProcessInstance> processInstanceList = historyService.createHistoricProcessInstanceQuery().processDefinitionName(subflowName).list();
1862 if (processInstanceList == null) {
1866 processInstanceList.sort((m1, m2) -> m1.getStartTime().compareTo(m2.getStartTime()));
1868 HistoricProcessInstance processInstance = processInstanceList.get(subflowInstanceIndex);
1870 HistoricVariableInstance v = historyService.createHistoricVariableInstanceQuery().processInstanceId(processInstance.getId())
1871 .variableName(variableName).singleResult();
1872 return v == null ? null : v.getValue();
1873 } catch (Exception e) {
1874 msoLogger.debug("Error retrieving variable " + variableName +
1875 " from " + subflowInstanceIndex + " instance index of sub flow: " + subflowName + ", Exception is: " + e);
1881 * Extracts text from an XML element. This method is not namespace aware
1882 * (namespaces are ignored). The first matching element is selected.
1883 * @param xml the XML document or fragment
1884 * @param tag the desired element, e.g. "<name>"
1885 * @return the element text, or null if the element was not found
1887 protected String getXMLTextElement(String xml, String tag) {
1888 xml = removeXMLNamespaces(xml);
1890 if (!tag.startsWith("<")) {
1891 tag = "<" + tag + ">";
1894 int start = xml.indexOf(tag);
1900 int end = xml.indexOf('<', start + tag.length());
1906 return xml.substring(start + tag.length(), end);
1910 * Removes namespace definitions and prefixes from XML, if any.
1912 private String removeXMLNamespaces(String xml) {
1913 // remove xmlns declaration
1914 xml = xml.replaceAll("xmlns.*?(\"|\').*?(\"|\')", "");
1916 // remove opening tag prefix
1917 xml = xml.replaceAll("(<)(\\w+:)(.*?>)", "$1$3");
1919 // remove closing tags prefix
1920 xml = xml.replaceAll("(</)(\\w+:)(.*?>)", "$1$3");
1922 // remove extra spaces left when xmlns declarations are removed
1923 xml = xml.replaceAll("\\s+>", ">");
1929 * Asserts that two XML documents are semantically equivalent. Differences
1930 * in whitespace or in namespace usage do not affect the comparison.
1931 * @param expected the expected XML
1932 * @param actual the XML to test
1933 * @throws SAXException
1934 * @throws IOException
1936 public static void assertXMLEquals(String expected, String actual)
1937 throws SAXException, IOException {
1938 XMLUnit.setIgnoreWhitespace(true);
1939 XMLUnit.setIgnoreAttributeOrder(true);
1940 DetailedDiff diff = new DetailedDiff(XMLUnit.compareXML(expected, actual));
1941 List<?> allDifferences = diff.getAllDifferences();
1942 assertEquals("Differences found: " + diff.toString(), 0, allDifferences.size());
1946 * A test implementation of AsynchronousResponse.
1948 public class TestAsyncResponse {
1949 Response response = null;
1954 public synchronized void setResponse(Response response) {
1955 this.response = response;
1959 * Gets the response.
1960 * @return the response, or null if none has been produced yet
1962 public synchronized Response getResponse() {
1968 * An object that contains callback data for a "program".
1970 public class CallbackSet {
1971 private final Map<String, CallbackData> map = new HashMap<>();
1974 * Add untyped callback data to the set.
1975 * @param action the action with which the data is associated
1976 * @param content the callback data
1978 public void put(String action, String content) {
1979 map.put(action, new CallbackData(null, null, content));
1983 * Add callback data to the set.
1984 * @param action the action with which the data is associated
1985 * @param messageType the callback message type
1986 * @param content the callback data
1988 public void put(String action, String messageType, String content) {
1989 map.put(action, new CallbackData(null, messageType, content));
1993 * Add callback data to the set.
1994 * @param action the action with which the data is associated
1995 * @param contentType the callback HTTP content type
1996 * @param messageType the callback message type
1997 * @param content the callback data
1999 public void put(String action, String contentType, String messageType, String content) {
2000 map.put(action, new CallbackData(contentType, messageType, content));
2004 * Retrieve callback data from the set.
2005 * @param action the action with which the data is associated
2006 * @return the callback data, or null if there is none for the specified operation
2008 public CallbackData get(String action) {
2009 return map.get(action);
2014 * Represents a callback data item.
2016 public class CallbackData {
2017 private final String contentType;
2018 private final String messageType;
2019 private final String content;
2023 * @param contentType the HTTP content type (optional)
2024 * @param messageType the callback message type (optional)
2025 * @param content the content
2027 public CallbackData(String contentType, String messageType, String content) {
2028 this.contentType = contentType;
2029 this.messageType = messageType;
2030 this.content = content;
2034 * Gets the callback HTTP content type, possibly null.
2036 public String getContentType() {
2041 * Gets the callback message type, possibly null.
2043 public String getMessageType() {
2048 * Gets the callback content.
2050 public String getContent() {
2056 * A tool for evaluating XPath expressions.
2058 protected class XPathTool {
2059 private final DocumentBuilderFactory factory;
2060 private final SimpleNamespaceContext context = new SimpleNamespaceContext();
2061 private final XPath xpath = XPathFactory.newInstance().newXPath();
2062 private String xml = null;
2063 private Document doc = null;
2068 public XPathTool() {
2069 factory = DocumentBuilderFactory.newInstance();
2070 factory.setNamespaceAware(true);
2071 xpath.setNamespaceContext(context);
2076 * @param prefix the namespace prefix
2077 * @param uri the namespace uri
2079 public synchronized void addNamespace(String prefix, String uri) {
2080 context.add(prefix, uri);
2084 * Sets the XML content to be operated on.
2085 * @param xml the XML content
2087 public synchronized void setXML(String xml) {
2093 * Returns the document object.
2094 * @return the document object, or null if XML has not been set
2095 * @throws SAXException
2096 * @throws IOException
2097 * @throws ParserConfigurationException
2099 public synchronized Document getDocument()
2100 throws ParserConfigurationException, IOException, SAXException {
2110 * Evaluates the specified XPath expression and returns a string result.
2111 * This method throws exceptions on error.
2112 * @param expression the expression
2113 * @return the result object
2114 * @throws ParserConfigurationException
2115 * @throws IOException
2116 * @throws SAXException
2117 * @throws XPathExpressionException on error
2119 public synchronized String evaluate(String expression)
2120 throws ParserConfigurationException, SAXException,
2121 IOException, XPathExpressionException {
2122 return (String) evaluate(expression, XPathConstants.STRING);
2126 * Evaluates the specified XPath expression.
2127 * This method throws exceptions on error.
2128 * @param expression the expression
2129 * @param returnType the return type
2130 * @return the result object
2131 * @throws ParserConfigurationException
2132 * @throws IOException
2133 * @throws SAXException
2134 * @throws XPathExpressionException on error
2136 public synchronized Object evaluate(String expression, QName returnType)
2137 throws ParserConfigurationException, SAXException,
2138 IOException, XPathExpressionException {
2141 XPathExpression expr = xpath.compile(expression);
2142 return expr.evaluate(doc, returnType);
2146 * Private helper method that builds the document object.
2147 * Assumes the calling method is synchronized.
2148 * @throws ParserConfigurationException
2149 * @throws IOException
2150 * @throws SAXException
2152 private void buildDocument() throws ParserConfigurationException,
2153 IOException, SAXException {
2156 throw new IOException("XML input is null");
2159 DocumentBuilder builder = factory.newDocumentBuilder();
2160 InputSource source = new InputSource(new StringReader(xml));
2161 doc = builder.parse(source);
2167 * A NamespaceContext class based on a Map.
2169 private class SimpleNamespaceContext implements NamespaceContext {
2170 private Map<String, String> prefixMap = new HashMap<>();
2171 private Map<String, String> uriMap = new HashMap<>();
2173 public synchronized void add(String prefix, String uri) {
2174 prefixMap.put(prefix, uri);
2175 uriMap.put(uri, prefix);
2179 public synchronized String getNamespaceURI(String prefix) {
2180 return prefixMap.get(prefix);
2184 public Iterator<String> getPrefixes(String uri) {
2185 List<String> list = new ArrayList<>();
2186 String prefix = uriMap.get(uri);
2187 if (prefix != null) {
2190 return list.iterator();
2194 public String getPrefix(String uri) {
2195 return uriMap.get(uri);
2200 * A VnfNotify XPathTool.
2202 protected class VnfNotifyXPathTool extends XPathTool {
2203 public VnfNotifyXPathTool() {
2204 addNamespace("tns", "http://org.onap.so/vnfNotify");
2209 * Helper class to make it easier to create this type.
2211 private static class CreateVnfNotificationOutputs
2212 extends CreateVnfNotification.Outputs {
2213 public void add(String key, String value) {
2214 Entry entry = new Entry();
2216 entry.setValue(value);
2217 getEntry().add(entry);
2222 * Helper class to make it easier to create this type.
2224 private static class UpdateVnfNotificationOutputs
2225 extends UpdateVnfNotification.Outputs {
2226 public void add(String key, String value) {
2227 Entry entry = new Entry();
2229 entry.setValue(value);
2230 getEntry().add(entry);