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";
148 public WorkflowTest() throws RuntimeException {
152 * The current request ID. Normally set when an "invoke" method is called.
154 protected volatile String msoRequestId = null;
157 * The current service instance ID. Normally set when an "invoke" method
160 protected volatile String msoServiceInstanceId = null;
163 * Logs a test start method.
165 protected void logStart() {
166 msoLogger.debug("STARTED TEST");
170 * Logs a test end method.
172 protected void logEnd() {
173 msoLogger.debug("ENDED TEST");
177 * Invokes a subprocess.
178 * @param processKey the process key
179 * @param businessKey a unique key that will identify the process instance
180 * @param injectedVariables variables to inject into the process
182 protected void invokeSubProcess(String processKey, String businessKey, Map<String, Object> injectedVariables) {
183 RuntimeMXBean runtimeMxBean = ManagementFactory.getRuntimeMXBean();
184 List<String> arguments = runtimeMxBean.getInputArguments();
185 msoLogger.debug("JVM args = " + arguments);
187 msoRequestId = (String) injectedVariables.get("mso-request-id");
188 String requestId = (String) injectedVariables.get("msoRequestId");
190 if (msoRequestId == null && requestId == null) {
191 String msg = "mso-request-id variable was not provided";
192 msoLogger.debug(msg);
196 // Note: some scenarios don't have a service-instance-id, may be null
197 msoServiceInstanceId = (String) injectedVariables.get("mso-service-instance-id");
200 runtimeService.startProcessInstanceByKey(processKey, businessKey, injectedVariables);
203 protected String invokeSubProcess(String processKey, Map<String, Object> injectedVariables) {
204 RuntimeMXBean runtimeMxBean = ManagementFactory.getRuntimeMXBean();
205 List<String> arguments = runtimeMxBean.getInputArguments();
206 msoLogger.debug("JVM args = " + arguments);
208 msoRequestId = (String) injectedVariables.get("mso-request-id");
209 String requestId = (String) injectedVariables.get("msoRequestId");
211 if (msoRequestId == null && requestId == null) {
212 String msg = "mso-request-id variable was not provided";
213 msoLogger.debug(msg);
217 // Note: some scenarios don't have a service-instance-id, may be null
218 msoServiceInstanceId = (String) injectedVariables.get("mso-service-instance-id");
221 ProcessInstance processInstance = runtimeService.startProcessInstanceByKey(processKey, msoRequestId, injectedVariables);
222 return processInstance.getId();
226 * Invokes an asynchronous process.
227 * Errors are handled with junit assertions and will cause the test to fail.
228 * @param processKey the process key
229 * @param schemaVersion the API schema version, e.g. "v1"
230 * @param businessKey a unique key that will identify the process instance
231 * @param request the request
232 * @return a TestAsyncResponse object associated with the test
233 * @throws InterruptedException
235 protected TestAsyncResponse invokeAsyncProcess(String processKey,
236 String schemaVersion, String businessKey, String request) throws InterruptedException {
237 return invokeAsyncProcess(processKey, schemaVersion, businessKey, request, null);
241 * Invokes an asynchronous process.
242 * Errors are handled with junit assertions and will cause the test to fail.
243 * @param processKey the process key
244 * @param schemaVersion the API schema version, e.g. "v1"
245 * @param businessKey a unique key that will identify the process instance
246 * @param request the request
247 * @param injectedVariables optional variables to inject into the process
248 * @return a TestAsyncResponse object associated with the test
249 * @throws InterruptedException
251 protected TestAsyncResponse invokeAsyncProcess(String processKey,
252 String schemaVersion, String businessKey, String request,
253 Map<String, Object> injectedVariables) {
255 RuntimeMXBean runtimeMxBean = ManagementFactory.getRuntimeMXBean();
256 List<String> arguments = runtimeMxBean.getInputArguments();
257 msoLogger.debug("JVM args = " + arguments);
259 Map<String, Object> variables = createVariables(schemaVersion, businessKey,
260 request, injectedVariables, false);
261 VariableMapImpl variableMapImpl = createVariableMapImpl(variables);
263 msoLogger.debug("Sending " + request + " to " + processKey + " process");
265 TestAsyncResponse asyncResponse = new TestAsyncResponse();
267 asyncResponse.setResponse(workflowResource.startProcessInstanceByKey( processKey, variableMapImpl));
269 return asyncResponse;
273 * Invokes an asynchronous process.
274 * Errors are handled with junit assertions and will cause the test to fail.
275 * @param processKey the process key
276 * @param schemaVersion the API schema version, e.g. "v1"
277 * @param businessKey a unique key that will identify the process instance
278 * @param request the request
279 * @param injectedVariables optional variables to inject into the process
280 * @param serviceInstantiationModel indicates whether this method is being
281 * invoked for a flow that is designed using the service instantiation model
282 * @return a TestAsyncResponse object associated with the test
283 * @throws InterruptedException
285 protected Response invokeAsyncProcess(String processKey,
286 String schemaVersion, String businessKey, String request,
287 Map<String, Object> injectedVariables, boolean serviceInstantiationModel) {
289 RuntimeMXBean runtimeMxBean = ManagementFactory.getRuntimeMXBean();
290 List<String> arguments = runtimeMxBean.getInputArguments();
291 msoLogger.debug("JVM args = " + arguments);
293 Map<String, Object> variables = createVariables(schemaVersion, businessKey,
294 request, injectedVariables, serviceInstantiationModel);
295 VariableMapImpl variableMapImpl = createVariableMapImpl(variables);
297 msoLogger.debug("Sending " + request + " to " + processKey + " process");
299 return workflowResource.startProcessInstanceByKey( processKey, variableMapImpl);
304 * Private helper method that creates a variable map for a request.
305 * Errors are handled with junit assertions and will cause the test to fail.
306 * @param schemaVersion the API schema version, e.g. "v1"
307 * @param businessKey a unique key that will identify the process instance
308 * @param request the request
309 * @param injectedVariables optional variables to inject into the process
310 * @param serviceInstantiationModel indicates whether this method is being
311 * invoked for a flow that is designed using the service instantiation model
312 * @return a variable map
314 private Map<String, Object> createVariables(String schemaVersion,
315 String businessKey, String request, Map<String, Object> injectedVariables,
316 boolean serviceInstantiationModel) {
318 Map<String, Object> variables = new HashMap<>();
320 // These variables may be overridded by injected variables.
321 variables.put("mso-service-request-timeout", "180");
322 variables.put("isDebugLogEnabled", "true");
324 // These variables may not be overridded by injected variables.
325 String[] notAllowed = new String[] {
326 "mso-schema-version",
330 "mso-service-instance-id"
333 if (injectedVariables != null) {
334 for (String key : injectedVariables.keySet()) {
335 for (String var : notAllowed) {
336 if (var.equals(key)) {
337 String msg = "Cannot specify " + var + " in injected variables";
338 msoLogger.debug(msg);
343 variables.put(key, injectedVariables.get(key));
347 variables.put("mso-schema-version", schemaVersion);
348 variables.put("mso-business-key", businessKey);
349 variables.put("bpmnRequest", request);
351 if (serviceInstantiationModel) {
354 * The request ID and the service instance ID are generated for flows
355 * that follow the service instantiation model unless "requestId" and
356 * "serviceInstanceId" are injected variables.
360 msoRequestId = (String) injectedVariables.get("requestId");
361 variables.put("mso-request-id", msoRequestId);
362 msoServiceInstanceId = (String) injectedVariables.get("serviceInstanceId");
363 variables.put("mso-service-instance-id", msoServiceInstanceId);
367 if (msoRequestId == null || msoRequestId.trim().equals("")) {
368 msoLogger.debug("No requestId element in injectedVariables");
369 variables.put("mso-request-id", UUID.randomUUID().toString());
371 if (msoServiceInstanceId == null || msoServiceInstanceId.trim().equals("")) {
372 msoLogger.debug("No seviceInstanceId element in injectedVariables");
373 variables.put("mso-service-instance-id", UUID.randomUUID().toString());
377 msoRequestId = getXMLTextElement(request, "request-id");
379 if (msoRequestId == null) {
380 //check in injected variables
382 msoRequestId = (String) injectedVariables.get("requestId");
386 if (msoRequestId == null || msoRequestId.trim().equals("")) {
387 String msg = "No request-id element in " + request;
388 msoLogger.debug(msg);
393 variables.put("mso-request-id", msoRequestId);
395 // Note: some request types don't have a service-instance-id
396 msoServiceInstanceId = getXMLTextElement(request, "service-instance-id");
398 if (msoServiceInstanceId != null) {
399 variables.put("mso-service-instance-id", msoServiceInstanceId);
407 * Private helper method that creates a camunda VariableMapImpl from a simple
409 * @param variables the simple variable map
410 * @return a VariableMap
412 private VariableMapImpl createVariableMapImpl(Map<String, Object> variables) {
413 Map<String, Object> wrappedVariables = new HashMap<>();
415 for (String key : variables.keySet()) {
416 Object value = variables.get(key);
417 wrappedVariables.put(key, wrapVariableValue(value));
420 VariableMapImpl variableMapImpl = new VariableMapImpl();
421 variableMapImpl.put("variables", wrappedVariables);
422 return variableMapImpl;
426 * Private helper method that wraps a variable value for inclusion in a
427 * camunda VariableMapImpl.
428 * @param value the variable value
429 * @return the wrapped variable
431 private Map<String, Object> wrapVariableValue(Object value) {
432 HashMap<String, Object> valueMap = new HashMap<>();
433 valueMap.put("value", value);
438 * Receives a response from an asynchronous process.
439 * Errors are handled with junit assertions and will cause the test to fail.
440 * @param businessKey the process business key
441 * @param asyncResponse the TestAsyncResponse object associated with the test
442 * @param timeout the timeout in milliseconds
443 * @return the WorkflowResponse
445 protected WorkflowResponse receiveResponse(String businessKey,
446 TestAsyncResponse asyncResponse, long timeout) {
447 msoLogger.debug("Waiting " + timeout + "ms for process with business key " + businessKey
448 + " to send a response");
450 long now = System.currentTimeMillis() + timeout;
451 long endTime = now + timeout;
453 while (now <= endTime) {
454 Response response = asyncResponse.getResponse();
456 if (response != null) {
457 msoLogger.debug("Received a response from process with business key " + businessKey);
459 Object entity = response.getEntity();
461 if (!(entity instanceof WorkflowResponse)) {
462 String msg = "Response entity is " +
463 (entity == null ? "null" : entity.getClass().getName()) +
464 ", expected WorkflowResponse";
465 msoLogger.debug(msg);
467 return null; // unreachable
470 return (WorkflowResponse) entity;
475 } catch (InterruptedException e) {
476 String msg = "Interrupted waiting for a response from process with business key " +
478 msoLogger.debug(msg);
480 return null; // unreachable
483 now = System.currentTimeMillis();
486 String msg = "No response received from process with business key " + businessKey +
487 " within " + timeout + "ms";
488 msoLogger.debug(msg);
489 fail("Process with business key " + businessKey + " did not end within 10000ms");
490 return null; // unreachable
494 * Runs a program to inject SDNC callback data into the test environment.
495 * A program is essentially just a list of keys that identify callback data
496 * to be injected, in sequence. An example program:
498 * reserve, assign, delete:ERR
500 * Errors are handled with junit assertions and will cause the test to fail.
501 * @param callbacks an object containing callback data for the program
502 * @param program the program to execute
504 protected void injectSDNCRestCallbacks(CallbackSet callbacks, String program) {
506 String[] cmds = program.replaceAll("\\s+", "").split(",");
508 for (String cmd : cmds) {
510 String modifier = "STD";
512 if (cmd.contains(":")) {
513 String[] parts = cmd.split(":");
518 String content = null;
519 String contentType = null;
521 if ("STD".equals(modifier)) {
522 CallbackData callbackData = callbacks.get(action);
524 if (callbackData == null) {
525 String msg = "No callback defined for '" + action + "' SDNC request";
526 msoLogger.debug(msg);
530 content = callbackData.getContent();
531 contentType = callbackData.getContentType();
532 } else if ("ERR".equals(modifier)) {
533 content = "{\"SDNCServiceError\":{\"sdncRequestId\":\"((REQUEST-ID))\",\"responseCode\":\"500\",\"responseMessage\":\"SIMULATED ERROR FROM SDNC ADAPTER\",\"ackFinalIndicator\":\"Y\"}}";
536 String msg = "Invalid SDNC program modifier: '" + modifier + "'";
537 msoLogger.debug(msg);
541 if (contentType == null) {
542 // Default for backward compatibility with existing tests.
546 if (!injectSDNCRestCallback(contentType, content, 10000)) {
547 fail("Failed to inject SDNC '" + action + "' callback");
552 } catch (InterruptedException e) {
553 fail("Interrupted after injection of SDNC '" + action + "' callback");
559 * Runs a program to inject SDNC events into the test environment.
560 * A program is essentially just a list of keys that identify event data
561 * to be injected, in sequence. An example program:
565 * NOTE: Each callback must have a message type associated with it, e.g.
567 * Errors are handled with junit assertions and will cause the test to fail.
568 * @param callbacks an object containing event data for the program
569 * @param program the program to execute
571 protected void injectSDNCEvents(CallbackSet callbacks, String program) {
572 injectWorkflowMessages(callbacks, program);
576 * Runs a program to inject SDNC callback data into the test environment.
577 * A program is essentially just a list of keys that identify callback data
578 * to be injected, in sequence. An example program:
580 * reserve, assign, delete:ERR
582 * Errors are handled with junit assertions and will cause the test to fail.
583 * @param callbacks an object containing callback data for the program
584 * @param program the program to execute
586 protected void injectSDNCCallbacks(CallbackSet callbacks, String program) {
588 String[] cmds = program.replaceAll("\\s+", "").split(",");
590 for (String cmd : cmds) {
592 String modifier = "STD";
594 if (cmd.contains(":")) {
595 String[] parts = cmd.split(":");
600 String content = null;
602 String respMsg = "OK";
604 if ("STD".equals(modifier)) {
605 CallbackData callbackData = callbacks.get(action);
607 if (callbackData == null) {
608 String msg = "No callback defined for '" + action + "' SDNC request";
609 msoLogger.debug(msg);
613 content = callbackData.getContent();
616 } else if ("CREATED".equals(modifier)) {
617 CallbackData callbackData = callbacks.get(action);
619 if (callbackData == null) {
620 String msg = "No callback defined for '" + action + "' SDNC request";
621 msoLogger.debug(msg);
625 content = callbackData.getContent();
628 } else if ("ERR".equals(modifier)) {
629 content = "<svc-request-id>((REQUEST-ID))</svc-request-id><response-code>500</response-code><response-message>SIMULATED ERROR FROM SDNC ADAPTER</response-message>";
631 respMsg = "SERVER ERROR";
633 String msg = "Invalid SDNC program modifier: '" + modifier + "'";
634 msoLogger.debug(msg);
638 if (!injectSDNCCallback(respCode, respMsg, content, 10000)) {
639 fail("Failed to inject SDNC '" + action + "' callback");
644 } catch (InterruptedException e) {
645 fail("Interrupted after injection of SDNC '" + action + "' callback");
651 * Runs a program to inject VNF adapter REST callback data into the test environment.
652 * A program is essentially just a list of keys that identify callback data
653 * to be injected, in sequence. An example program:
657 * Errors are handled with junit assertions and will cause the test to fail.
658 * @param callbacks an object containing callback data for the program
659 * @param program the program to execute
661 protected void injectVNFRestCallbacks(CallbackSet callbacks, String program) {
663 String[] cmds = program.replaceAll("\\s+", "").split(",");
665 for (String cmd : cmds) {
667 String modifier = "STD";
669 if (cmd.contains(":")) {
670 String[] parts = cmd.split(":");
675 String content = null;
676 String contentType = null;
678 if ("STD".equals(modifier)) {
679 CallbackData callbackData = callbacks.get(action);
681 if (callbackData == null) {
682 String msg = "No callback defined for '" + action + "' VNF REST request";
683 msoLogger.debug(msg);
687 content = callbackData.getContent();
688 contentType = callbackData.getContentType();
689 } else if ("ERR".equals(modifier)) {
690 content = "SIMULATED ERROR FROM VNF ADAPTER";
691 contentType = "text/plain";
693 String msg = "Invalid VNF REST program modifier: '" + modifier + "'";
694 msoLogger.debug(msg);
698 if (contentType == null) {
699 // Default for backward compatibility with existing tests.
703 if (!injectVnfAdapterRestCallback(contentType, content, 10000)) {
704 fail("Failed to inject VNF REST '" + action + "' callback");
709 } catch (InterruptedException e) {
710 fail("Interrupted after injection of VNF REST '" + action + "' callback");
716 * Runs a program to inject VNF callback data into the test environment.
717 * A program is essentially just a list of keys that identify callback data
718 * to be injected, in sequence. An example program:
720 * createVnf, deleteVnf
722 * Errors are handled with junit assertions and will cause the test to fail.
723 * @param callbacks an object containing callback data for the program
724 * @param program the program to execute
726 protected void injectVNFCallbacks(CallbackSet callbacks, String program) {
728 String[] cmds = program.replaceAll("\\s+", "").split(",");
730 for (String cmd : cmds) {
732 String modifier = "STD";
734 if (cmd.contains(":")) {
735 String[] parts = cmd.split(":");
740 String content = null;
742 if ("STD".equals(modifier)) {
743 CallbackData callbackData = callbacks.get(action);
745 if (callbackData == null) {
746 String msg = "No callback defined for '" + action + "' VNF request";
747 msoLogger.debug(msg);
751 content = callbackData.getContent();
752 } else if ("ERR".equals(modifier)) {
753 String msg = "Currently unsupported VNF program modifier: '" + modifier + "'";
754 msoLogger.debug(msg);
757 String msg = "Invalid VNF program modifier: '" + modifier + "'";
758 msoLogger.debug(msg);
762 boolean injected = false;
764 if (content.contains("createVnfNotification")) {
765 injected = injectCreateVNFCallback(content, 10000);
766 } else if (content.contains("deleteVnfNotification")) {
767 injected = injectDeleteVNFCallback(content, 10000);
768 } else if (content.contains("updateVnfNotification")) {
769 injected = injectUpdateVNFCallback(content, 10000);
773 String msg = "Failed to inject VNF '" + action + "' callback";
774 msoLogger.debug(msg);
780 } catch (InterruptedException e) {
781 fail("Interrupted after injection of VNF '" + action + "' callback");
787 * Waits for the number of running processes with the specified process
788 * definition key to equal a particular count.
789 * @param processKey the process definition key
790 * @param count the desired count
791 * @param timeout the timeout in milliseconds
793 protected void waitForRunningProcessCount(String processKey, int count, long timeout) {
794 msoLogger.debug("Waiting " + timeout + "ms for there to be " + count + " "
795 + processKey + " instances");
797 long now = System.currentTimeMillis() + timeout;
798 long endTime = now + timeout;
801 while (now <= endTime) {
802 int actual = runtimeService
803 .createProcessInstanceQuery()
804 .processDefinitionKey(processKey)
807 if (actual != last) {
808 msoLogger.debug("There are now " + actual + " "
809 + processKey + " instances");
813 if (actual == count) {
819 } catch (InterruptedException e) {
820 String msg = "Interrupted waiting for there to be " + count + " "
821 + processKey + " instances";
822 msoLogger.debug(msg);
826 now = System.currentTimeMillis();
829 String msg = "Timed out waiting for there to be " + count + " "
830 + processKey + " instances";
831 msoLogger.debug(msg);
836 * Waits for the specified process variable to be set.
837 * @param processKey the process definition key
838 * @param variable the variable name
839 * @param timeout the timeout in milliseconds
840 * @return the variable value, or null if it cannot be obtained
841 * in the specified time
843 protected Object getProcessVariable(String processKey, String variable,
846 msoLogger.debug("Waiting " + timeout + "ms for "
847 + processKey + "." + variable + " to be set");
849 long now = System.currentTimeMillis() + timeout;
850 long endTime = now + timeout;
852 ProcessInstance processInstance = null;
855 while (value == null) {
857 if (processInstance == null) {
858 msoLogger.debug("Timed out waiting for "
859 + processKey + " to start");
861 msoLogger.debug("Timed out waiting for "
862 + processKey + "[" + processInstance.getId()
863 + "]." + variable + " to be set");
869 if (processInstance == null) {
870 processInstance = runtimeService
871 .createProcessInstanceQuery()
872 .processDefinitionKey(processKey)
876 if (processInstance != null) {
877 value = runtimeService
878 .getVariable(processInstance.getId(), variable);
883 } catch (InterruptedException e) {
884 msoLogger.debug("Interrupted waiting for "
885 + processKey + "." + variable + " to be set");
889 now = System.currentTimeMillis();
892 msoLogger.debug(processKey + "["
893 + processInstance.getId() + "]." + variable + "="
900 * Injects a single SDNC adapter callback request. The specified callback data
901 * may contain the placeholder string ((REQUEST-ID)) which is replaced with
902 * the actual SDNC request ID. Note: this is not the requestId in the original
904 * @param contentType the HTTP content type for the callback
905 * @param content the content of the callback
906 * @param timeout the timeout in milliseconds
907 * @return true if the callback could be injected, false otherwise
909 protected boolean injectSDNCRestCallback(String contentType, String content, long timeout) {
910 String sdncRequestId = (String) getProcessVariable("SDNCAdapterRestV1",
911 "SDNCAResponse_CORRELATOR", timeout);
913 if (sdncRequestId == null) {
917 content = content.replace("((REQUEST-ID))", sdncRequestId);
918 // Deprecated usage. All test code should switch to the (( ... )) syntax.
919 content = content.replace("{{REQUEST-ID}}", sdncRequestId);
921 msoLogger.debug("Injecting SDNC adapter callback");
923 Response response = workflowMessageResource.deliver(contentType, "SDNCAResponse", sdncRequestId, content);
924 msoLogger.debug("Workflow response to SDNC adapter callback: " + response);
929 * Injects a single SDNC adapter callback request. The specified callback data
930 * may contain the placeholder string ((REQUEST-ID)) which is replaced with
931 * the actual SDNC request ID. Note: this is not the requestId in the original
933 * @param content the content of the callback
934 * @param respCode the response code (normally 200)
935 * @param respMsg the response message (normally "OK")
936 * @param timeout the timeout in milliseconds
937 * @return true if the callback could be injected, false otherwise
939 protected boolean injectSDNCCallback(int respCode, String respMsg,
940 String content, long timeout) {
942 String sdncRequestId = (String) getProcessVariable("sdncAdapter",
943 "SDNCA_requestId", timeout);
945 if (sdncRequestId == null) {
949 content = content.replace("((REQUEST-ID))", sdncRequestId);
950 // Deprecated usage. All test code should switch to the (( ... )) syntax.
951 content = content.replace("{{REQUEST-ID}}", sdncRequestId);
953 // TODO this needs to be fixed. It is causing double tags and content
954 // Need to parse content before setting below since content includes not just RequestData or modify callback files to only contain RequestData contents.
956 msoLogger.debug("Injecting SDNC adapter callback");
957 CallbackHeader callbackHeader = new CallbackHeader();
958 callbackHeader.setRequestId(sdncRequestId);
959 callbackHeader.setResponseCode(String.valueOf(respCode));
960 callbackHeader.setResponseMessage(respMsg);
961 SDNCAdapterCallbackRequest sdncAdapterCallbackRequest = new SDNCAdapterCallbackRequest();
962 sdncAdapterCallbackRequest.setCallbackHeader(callbackHeader);
963 sdncAdapterCallbackRequest.setRequestData(content);
964 SDNCAdapterResponse sdncAdapterResponse = callbackService.sdncAdapterCallback(sdncAdapterCallbackRequest);
965 msoLogger.debug("Workflow response to SDNC adapter callback: " + sdncAdapterResponse);
971 * Injects a single VNF adapter callback request. The specified callback data
972 * may contain the placeholder string ((MESSAGE-ID)) which is replaced with
973 * the actual message ID. Note: this is not the requestId in the original
975 * @param contentType the HTTP content type for the callback
976 * @param content the content of the callback
977 * @param timeout the timeout in milliseconds
978 * @return true if the callback could be injected, false otherwise
980 protected boolean injectVnfAdapterRestCallback(String contentType, String content, long timeout) {
981 String messageId = (String) getProcessVariable("vnfAdapterRestV1",
982 "VNFAResponse_CORRELATOR", timeout);
984 if (messageId == null) {
988 content = content.replace("((MESSAGE-ID))", messageId);
989 // Deprecated usage. All test code should switch to the (( ... )) syntax.
990 content = content.replace("{{MESSAGE-ID}}", messageId);
992 msoLogger.debug("Injecting VNF adapter callback");
994 Response response = workflowMessageResource.deliver(contentType, "VNFAResponse", messageId, content);
995 msoLogger.debug("Workflow response to VNF adapter callback: " + response);
1000 * Injects a Create VNF adapter callback request. The specified callback data
1001 * may contain the placeholder string ((MESSAGE-ID)) which is replaced with
1002 * the actual message ID. It may also contain the placeholder string
1003 * ((REQUEST-ID)) which is replaced request ID of the original MSO request.
1004 * @param content the content of the callback
1005 * @param timeout the timeout in milliseconds
1006 * @return true if the callback could be injected, false otherwise
1007 * @throws JAXBException if the content does not adhere to the schema
1009 protected boolean injectCreateVNFCallback(String content, long timeout) {
1011 String messageId = (String) getProcessVariable("vnfAdapterCreateV1",
1012 "VNFC_messageId", timeout);
1014 if (messageId == null) {
1018 content = content.replace("((MESSAGE-ID))", messageId);
1019 // Deprecated usage. All test code should switch to the (( ... )) syntax.
1020 content = content.replace("{{MESSAGE-ID}}", messageId);
1022 if(content.contains("((REQUEST-ID))")){
1023 content = content.replace("((REQUEST-ID))", msoRequestId);
1024 // Deprecated usage. All test code should switch to the (( ... )) syntax.
1025 content = content.replace("{{REQUEST-ID}}", msoRequestId);
1028 msoLogger.debug("Injecting VNF adapter callback");
1030 // Is it possible to unmarshal this with JAXB? I couldn't.
1032 CreateVnfNotification createVnfNotification = new CreateVnfNotification();
1033 XPathTool xpathTool = new VnfNotifyXPathTool();
1034 xpathTool.setXML(content);
1037 String completed = xpathTool.evaluate(
1038 "/tns:createVnfNotification/tns:completed/text()");
1039 createVnfNotification.setCompleted("true".equals(completed));
1041 String vnfId = xpathTool.evaluate(
1042 "/tns:createVnfNotification/tns:vnfId/text()");
1043 createVnfNotification.setVnfId(vnfId);
1045 NodeList entries = (NodeList) xpathTool.evaluate(
1046 "/tns:createVnfNotification/tns:outputs/tns:entry",
1047 XPathConstants.NODESET);
1049 CreateVnfNotificationOutputs outputs = new CreateVnfNotificationOutputs();
1051 for (int i = 0; i < entries.getLength(); i++) {
1052 Node node = entries.item(i);
1054 if (node.getNodeType() == Node.ELEMENT_NODE) {
1055 Element entry = (Element) node;
1056 String key = entry.getElementsByTagNameNS("*", "key").item(0).getTextContent();
1057 String value = entry.getElementsByTagNameNS("*", "value").item(0).getTextContent();
1058 outputs.add(key, value);
1062 createVnfNotification.setOutputs(outputs);
1064 VnfRollback rollback = new VnfRollback();
1066 String cloudSiteId = xpathTool.evaluate(
1067 "/tns:createVnfNotification/tns:rollback/tns:cloudSiteId/text()");
1068 rollback.setCloudSiteId(cloudSiteId);
1070 String requestId = xpathTool.evaluate(
1071 "/tns:createVnfNotification/tns:rollback/tns:msoRequest/tns:requestId/text()");
1072 String serviceInstanceId = xpathTool.evaluate(
1073 "/tns:createVnfNotification/tns:rollback/tns:msoRequest/tns:serviceInstanceId/text()");
1075 if (requestId != null || serviceInstanceId != null) {
1076 MsoRequest msoRequest = new MsoRequest();
1077 msoRequest.setRequestId(requestId);
1078 msoRequest.setServiceInstanceId(serviceInstanceId);
1079 rollback.setMsoRequest(msoRequest);
1082 String tenantCreated = xpathTool.evaluate(
1083 "/tns:createVnfNotification/tns:rollback/tns:tenantCreated/text()");
1084 rollback.setTenantCreated("true".equals(tenantCreated));
1086 String tenantId = xpathTool.evaluate(
1087 "/tns:createVnfNotification/tns:rollback/tns:tenantId/text()");
1088 rollback.setTenantId(tenantId);
1090 String vnfCreated = xpathTool.evaluate(
1091 "/tns:createVnfNotification/tns:rollback/tns:vnfCreated/text()");
1092 rollback.setVnfCreated("true".equals(vnfCreated));
1094 String rollbackVnfId = xpathTool.evaluate(
1095 "/tns:createVnfNotification/tns:rollback/tns:vnfId/text()");
1096 rollback.setVnfId(rollbackVnfId);
1098 createVnfNotification.setRollback(rollback);
1100 } catch (Exception e) {
1101 msoLogger.debug("Failed to unmarshal VNF callback content:");
1102 msoLogger.debug(content);
1106 VnfAdapterNotifyServiceImpl notifyService = new VnfAdapterNotifyServiceImpl();
1109 notifyService.createVnfNotification(
1111 createVnfNotification.isCompleted(),
1112 createVnfNotification.getException(),
1113 createVnfNotification.getErrorMessage(),
1114 createVnfNotification.getVnfId(),
1115 createVnfNotification.getOutputs(),
1116 createVnfNotification.getRollback());
1122 * Injects a Delete VNF adapter callback request. The specified callback data
1123 * may contain the placeholder string ((MESSAGE-ID)) which is replaced with
1124 * the actual message ID. It may also contain the placeholder string
1125 * ((REQUEST-ID)) which is replaced request ID of the original MSO request.
1126 * @param content the content of the callback
1127 * @param timeout the timeout in milliseconds
1128 * @return true if the callback could be injected, false otherwise
1129 * @throws JAXBException if the content does not adhere to the schema
1131 protected boolean injectDeleteVNFCallback(String content, long timeout) {
1133 String messageId = (String) getProcessVariable("vnfAdapterDeleteV1",
1134 "VNFDEL_uuid", timeout);
1136 if (messageId == null) {
1140 content = content.replace("((MESSAGE-ID))", messageId);
1141 // Deprecated usage. All test code should switch to the (( ... )) syntax.
1142 content = content.replace("{{MESSAGE-ID}}", messageId);
1144 msoLogger.debug("Injecting VNF adapter delete callback");
1146 // Is it possible to unmarshal this with JAXB? I couldn't.
1148 DeleteVnfNotification deleteVnfNotification = new DeleteVnfNotification();
1149 XPathTool xpathTool = new VnfNotifyXPathTool();
1150 xpathTool.setXML(content);
1153 String completed = xpathTool.evaluate(
1154 "/tns:deleteVnfNotification/tns:completed/text()");
1155 deleteVnfNotification.setCompleted("true".equals(completed));
1156 // if notification failure, set the exception and error message
1157 if (deleteVnfNotification.isCompleted() == false) {
1158 deleteVnfNotification.setException(MsoExceptionCategory.INTERNAL);
1159 deleteVnfNotification.setErrorMessage(xpathTool.evaluate(
1160 "/tns:deleteVnfNotification/tns:errorMessage/text()")) ;
1163 } catch (Exception e) {
1164 msoLogger.debug("Failed to unmarshal VNF Delete callback content:");
1165 msoLogger.debug(content);
1169 VnfAdapterNotifyServiceImpl notifyService = new VnfAdapterNotifyServiceImpl();
1172 notifyService.deleteVnfNotification(
1174 deleteVnfNotification.isCompleted(),
1175 deleteVnfNotification.getException(),
1176 deleteVnfNotification.getErrorMessage());
1182 * Injects a Update VNF adapter callback request. The specified callback data
1183 * may contain the placeholder string ((MESSAGE-ID)) which is replaced with
1184 * the actual message ID. It may also contain the placeholder string
1185 * ((REQUEST-ID)) which is replaced request ID of the original MSO request.
1186 * @param content the content of the callback
1187 * @param timeout the timeout in milliseconds
1188 * @return true if the callback could be injected, false otherwise
1189 * @throws JAXBException if the content does not adhere to the schema
1191 protected boolean injectUpdateVNFCallback(String content, long timeout) {
1193 String messageId = (String) getProcessVariable("vnfAdapterUpdate",
1194 "VNFU_messageId", timeout);
1196 if (messageId == null) {
1200 content = content.replace("((MESSAGE-ID))", messageId);
1201 // Deprecated usage. All test code should switch to the (( ... )) syntax.
1202 content = content.replace("{{MESSAGE-ID}}", messageId);
1204 content = content.replace("((REQUEST-ID))", msoRequestId);
1205 // Deprecated usage. All test code should switch to the (( ... )) syntax.
1206 content = content.replace("{{REQUEST-ID}}", msoRequestId);
1208 msoLogger.debug("Injecting VNF adapter callback");
1210 // Is it possible to unmarshal this with JAXB? I couldn't.
1212 UpdateVnfNotification updateVnfNotification = new UpdateVnfNotification();
1213 XPathTool xpathTool = new VnfNotifyXPathTool();
1214 xpathTool.setXML(content);
1217 String completed = xpathTool.evaluate(
1218 "/tns:updateVnfNotification/tns:completed/text()");
1219 updateVnfNotification.setCompleted("true".equals(completed));
1221 NodeList entries = (NodeList) xpathTool.evaluate(
1222 "/tns:updateVnfNotification/tns:outputs/tns:entry",
1223 XPathConstants.NODESET);
1225 UpdateVnfNotificationOutputs outputs = new UpdateVnfNotificationOutputs();
1227 for (int i = 0; i < entries.getLength(); i++) {
1228 Node node = entries.item(i);
1230 if (node.getNodeType() == Node.ELEMENT_NODE) {
1231 Element entry = (Element) node;
1232 String key = entry.getElementsByTagNameNS("*", "key").item(0).getTextContent();
1233 String value = entry.getElementsByTagNameNS("*", "value").item(0).getTextContent();
1234 outputs.add(key, value);
1238 updateVnfNotification.setOutputs(outputs);
1240 VnfRollback rollback = new VnfRollback();
1242 String cloudSiteId = xpathTool.evaluate(
1243 "/tns:updateVnfNotification/tns:rollback/tns:cloudSiteId/text()");
1244 rollback.setCloudSiteId(cloudSiteId);
1246 String requestId = xpathTool.evaluate(
1247 "/tns:updateVnfNotification/tns:rollback/tns:msoRequest/tns:requestId/text()");
1248 String serviceInstanceId = xpathTool.evaluate(
1249 "/tns:updateVnfNotification/tns:rollback/tns:msoRequest/tns:serviceInstanceId/text()");
1251 if (requestId != null || serviceInstanceId != null) {
1252 MsoRequest msoRequest = new MsoRequest();
1253 msoRequest.setRequestId(requestId);
1254 msoRequest.setServiceInstanceId(serviceInstanceId);
1255 rollback.setMsoRequest(msoRequest);
1258 String tenantCreated = xpathTool.evaluate(
1259 "/tns:updateVnfNotification/tns:rollback/tns:tenantCreated/text()");
1260 rollback.setTenantCreated("true".equals(tenantCreated));
1262 String tenantId = xpathTool.evaluate(
1263 "/tns:updateVnfNotification/tns:rollback/tns:tenantId/text()");
1264 rollback.setTenantId(tenantId);
1266 String vnfCreated = xpathTool.evaluate(
1267 "/tns:updateVnfNotification/tns:rollback/tns:vnfCreated/text()");
1268 rollback.setVnfCreated("true".equals(vnfCreated));
1270 String rollbackVnfId = xpathTool.evaluate(
1271 "/tns:updateVnfNotification/tns:rollback/tns:vnfId/text()");
1272 rollback.setVnfId(rollbackVnfId);
1274 updateVnfNotification.setRollback(rollback);
1276 } catch (Exception e) {
1277 msoLogger.debug("Failed to unmarshal VNF callback content:");
1278 msoLogger.debug(content);
1282 VnfAdapterNotifyServiceImpl notifyService = new VnfAdapterNotifyServiceImpl();
1285 notifyService.updateVnfNotification(
1287 updateVnfNotification.isCompleted(),
1288 updateVnfNotification.getException(),
1289 updateVnfNotification.getErrorMessage(),
1290 updateVnfNotification.getOutputs(),
1291 updateVnfNotification.getRollback());
1297 * Runs a program to inject workflow messages into the test environment.
1298 * A program is essentially just a list of keys that identify event data
1299 * to be injected, in sequence. An example program:
1303 * Errors are handled with junit assertions and will cause the test to fail.
1304 * NOTE: Each callback must have a workflow message type associated with it.
1305 * @param callbacks an object containing event data for the program
1306 * @param program the program to execute
1308 protected void injectWorkflowMessages(CallbackSet callbacks, String program) {
1310 String[] cmds = program.replaceAll("\\s+", "").split(",");
1312 for (String cmd : cmds) {
1313 String action = cmd;
1314 String modifier = "STD";
1316 if (cmd.contains(":")) {
1317 String[] parts = cmd.split(":");
1319 modifier = parts[1];
1322 String messageType = null;
1323 String content = null;
1324 String contentType = null;
1326 if ("STD".equals(modifier)) {
1327 CallbackData callbackData = callbacks.get(action);
1329 if (callbackData == null) {
1330 String msg = "No '" + action + "' workflow message callback is defined";
1331 msoLogger.debug(msg);
1335 messageType = callbackData.getMessageType();
1337 if (messageType == null || messageType.trim().equals("")) {
1338 String msg = "No workflow message type is defined in the '" + action + "' callback";
1339 msoLogger.debug(msg);
1343 content = callbackData.getContent();
1344 contentType = callbackData.getContentType();
1346 String msg = "Invalid workflow message program modifier: '" + modifier + "'";
1347 msoLogger.debug(msg);
1351 if (!injectWorkflowMessage(contentType, messageType, content, 10000)) {
1352 fail("Failed to inject '" + action + "' workflow message");
1357 } catch (InterruptedException e) {
1358 fail("Interrupted after injection of '" + action + "' workflow message");
1364 * Injects a workflow message. The specified callback data may contain the
1365 * placeholder string ((CORRELATOR)) which is replaced with the actual
1367 * @param contentType the HTTP contentType for the message (possibly null)
1368 * @param messageType the message type
1369 * @param content the message content (possibly null)
1370 * @param timeout the timeout in milliseconds
1371 * @return true if the message could be injected, false otherwise
1373 protected boolean injectWorkflowMessage(String contentType, String messageType, String content, long timeout) {
1374 String correlator = (String) getProcessVariable("ReceiveWorkflowMessage",
1375 messageType + "_CORRELATOR", timeout);
1377 if (correlator == null) {
1381 if (content != null) {
1382 content = content.replace("((CORRELATOR))", correlator);
1385 msoLogger.debug("Injecting " + messageType + " message");
1387 Response response = workflowMessageResource.deliver(contentType, messageType, correlator, content);
1388 msoLogger.debug("Workflow response to " + messageType + " message: " + response);
1393 * Runs a program to inject sniro workflow messages into the test environment.
1394 * A program is essentially just a list of keys that identify event data
1395 * to be injected, in sequence. For more details, see
1396 * injectSNIROCallbacks(String contentType, String messageType, String content, long timeout)
1398 * Errors are handled with junit assertions and will cause the test to fail.
1399 * NOTE: Each callback must have a workflow message type associated with it.
1401 * @param callbacks an object containing event data for the program
1402 * @param program the program to execute
1404 protected void injectSNIROCallbacks(CallbackSet callbacks, String program) {
1406 String[] cmds = program.replaceAll("\\s+", "").split(",");
1408 for (String cmd : cmds) {
1409 String action = cmd;
1410 String modifier = "STD";
1412 if (cmd.contains(":")) {
1413 String[] parts = cmd.split(":");
1415 modifier = parts[1];
1418 String messageType = null;
1419 String content = null;
1420 String contentType = null;
1422 if ("STD".equals(modifier)) {
1423 CallbackData callbackData = callbacks.get(action);
1425 if (callbackData == null) {
1426 String msg = "No '" + action + "' workflow message callback is defined";
1427 msoLogger.debug(msg);
1431 messageType = callbackData.getMessageType();
1433 if (messageType == null || messageType.trim().equals("")) {
1434 String msg = "No workflow message type is defined in the '" + action + "' callback";
1435 msoLogger.debug(msg);
1439 content = callbackData.getContent();
1440 contentType = callbackData.getContentType();
1442 String msg = "Invalid workflow message program modifier: '" + modifier + "'";
1443 msoLogger.debug(msg);
1447 if (!injectSNIROCallbacks(contentType, messageType, content, 10000)) {
1448 fail("Failed to inject '" + action + "' workflow message");
1453 } catch (InterruptedException e) {
1454 fail("Interrupted after injection of '" + action + "' workflow message");
1460 * Injects a sniro workflow message. The specified callback response may
1461 * contain the placeholder strings ((CORRELATOR)) and ((SERVICE_RESOURCE_ID))
1462 * The ((CORRELATOR)) is replaced with the actual correlator value from the
1463 * request. The ((SERVICE_RESOURCE_ID)) is replaced with the actual serviceResourceId
1464 * value from the sniro request. Currently this only works with sniro request
1465 * that contain only 1 resource.
1467 * @param contentType the HTTP contentType for the message (possibly null)
1468 * @param messageType the message type
1469 * @param content the message content (possibly null)
1470 * @param timeout the timeout in milliseconds
1471 * @return true if the message could be injected, false otherwise
1473 protected boolean injectSNIROCallbacks(String contentType, String messageType, String content, long timeout) {
1474 String correlator = (String) getProcessVariable("ReceiveWorkflowMessage",
1475 messageType + "_CORRELATOR", timeout);
1477 if (correlator == null) {
1480 if (content != null) {
1481 content = content.replace("((CORRELATOR))", correlator);
1482 if(messageType.equalsIgnoreCase("SNIROResponse")){
1483 ServiceDecomposition decomp = (ServiceDecomposition) getProcessVariable("Homing", "serviceDecomposition", timeout);
1484 List<Resource> resourceList = decomp.getServiceResources();
1485 if(resourceList.size() == 1){
1486 String resourceId = "";
1487 for(Resource resource:resourceList){
1488 resourceId = resource.getResourceId();
1490 String homingList = getJsonValue(content, "solutionInfo.placement");
1491 JSONArray placementArr = null;
1493 placementArr = new JSONArray(homingList);
1495 catch (Exception e) {
1498 if(placementArr.length() == 1){
1499 content = content.replace("((SERVICE_RESOURCE_ID))", resourceId);
1501 String licenseInfoList = getJsonValue(content, "solutionInfo.licenseInfo");
1502 JSONArray licenseArr = null;
1504 licenseArr = new JSONArray(licenseInfoList);
1506 catch (Exception e) {
1509 if(licenseArr.length() == 1){
1510 content = content.replace("((SERVICE_RESOURCE_ID))", resourceId);
1515 String homingList = getJsonValue(content, "solutionInfo.placementInfo");
1516 String licenseInfoList = getJsonValue(content, "solutionInfo.licenseInfo");
1517 JSONArray placementArr = new JSONArray(homingList);
1518 JSONArray licenseArr = new JSONArray(licenseInfoList);
1519 for (Resource resource: resourceList) {
1520 String resourceModuleName = resource.getModelInfo().getModelInstanceName();
1521 String resourceId = resource.getResourceId();
1523 for (int i=0; i<placementArr.length(); i++) {
1524 JSONObject placementObj = placementArr.getJSONObject(i);
1525 String placementModuleName = placementObj.getString("resourceModuleName");
1526 if (placementModuleName.equalsIgnoreCase(resourceModuleName)) {
1527 String placementString = placementObj.toString();
1528 placementString = placementString.replace("((SERVICE_RESOURCE_ID))", resourceId);
1529 JSONObject newPlacementObj = new JSONObject(placementString);
1530 placementArr.put(i, newPlacementObj);
1534 for (int i=0; i<licenseArr.length(); i++) {
1535 JSONObject licenseObj = licenseArr.getJSONObject(i);
1536 String licenseModuleName = licenseObj.getString("resourceModuleName");
1537 if (licenseModuleName.equalsIgnoreCase(resourceModuleName)) {
1538 String licenseString = licenseObj.toString();
1539 licenseString = licenseString.replace("((SERVICE_RESOURCE_ID))", resourceId);
1540 JSONObject newLicenseObj = new JSONObject(licenseString);
1541 licenseArr.put(i, newLicenseObj);
1545 String newPlacementInfos = placementArr.toString();
1546 String newLicenseInfos = licenseArr.toString();
1547 content = updJsonValue(content, "solutionInfo.placementInfo", newPlacementInfos);
1548 content = updJsonValue(content, "solutionInfo.licenseInfo", newLicenseInfos);
1550 catch(Exception e) {
1557 msoLogger.debug("Injecting " + messageType + " message");
1559 Response response = workflowMessageResource.deliver(contentType, messageType, correlator, content);
1560 msoLogger.debug("Workflow response to " + messageType + " message: " + response);
1566 * Wait for the process to end.
1567 * @param businessKey the process business key
1568 * @param timeout the amount of time to wait, in milliseconds
1570 protected void waitForProcessEnd(String businessKey, long timeout) {
1571 msoLogger.debug("Waiting " + timeout + "ms for process with business key " +
1572 businessKey + " to end");
1574 long now = System.currentTimeMillis() + timeout;
1575 long endTime = now + timeout;
1577 while (now <= endTime) {
1578 if (isProcessEnded(businessKey)) {
1579 msoLogger.debug("Process with business key " + businessKey + " has ended");
1585 } catch (InterruptedException e) {
1586 String msg = "Interrupted waiting for process with business key " +
1587 businessKey + " to end";
1588 msoLogger.debug(msg);
1592 now = System.currentTimeMillis();
1595 String msg = "Process with business key " + businessKey +
1596 " did not end within " + timeout + "ms";
1597 msoLogger.debug(msg);
1602 * Wait for the process to end. Must be used when multiple process instances exist with
1603 * this same business key such as when its passed to subflows or shared across multiple
1606 * @param businessKey the process business key
1607 * @param processName the process definition name
1608 * @param timeout the amount of time to wait, in milliseconds
1611 protected void waitForProcessEnd(String businessKey, String processName, long timeout) {
1612 msoLogger.debug("Waiting " + timeout + "ms for process with business key " +
1613 businessKey + " to end");
1615 long now = System.currentTimeMillis() + timeout;
1616 long endTime = now + timeout;
1618 while (now <= endTime) {
1619 if (isProcessEnded(businessKey, processName)) {
1620 msoLogger.debug("Process with business key " + businessKey + " has ended");
1626 } catch (InterruptedException e) {
1627 String msg = "Interrupted waiting for process with business key " +
1628 businessKey + " to end";
1629 msoLogger.debug(msg);
1633 now = System.currentTimeMillis();
1636 String msg = "Process with business key " + businessKey +
1637 " did not end within " + timeout + "ms";
1638 msoLogger.debug(msg);
1643 * Verifies that the specified historic process variable has the specified value.
1644 * If the variable does not have the specified value, the test is failed.
1646 * @param businessKey the process business key
1647 * @param variable the variable name
1648 * @param value the expected variable value
1650 protected void checkVariable(String businessKey, String variable, Object value) {
1651 if (!isProcessEnded(businessKey)) {
1652 fail("Cannot get historic variable " + variable + " because process with business key " +
1653 businessKey + " has not ended");
1656 Object variableValue = getVariableFromHistory(businessKey, variable);
1657 assertEquals(value, variableValue);
1661 * Checks to see if the specified process is ended.
1662 * @param businessKey the process business Key
1663 * @return true if the process is ended
1665 protected boolean isProcessEnded(String businessKey) {
1666 HistoricProcessInstance processInstance = historyService
1667 .createHistoricProcessInstanceQuery().processInstanceBusinessKey(businessKey).singleResult();
1668 return processInstance != null && processInstance.getEndTime() != null;
1672 * Checks to see if the specified process is ended.
1673 <<<<<<< HEAD:bpmn/mso-infrastructure-bpmn/src/test/java/org/onap/so/bpmn/common/WorkflowTest.java
1674 * @param processInstanceId the process Instance Id
1675 * @return true if the process is ended
1677 protected boolean isProcessEndedByProcessInstanceId(String processInstanceId) {
1678 HistoricProcessInstance processInstance = historyService
1679 .createHistoricProcessInstanceQuery().processInstanceId(processInstanceId).singleResult();
1680 return processInstance != null && processInstance.getEndTime() != null;
1684 * Checks to see if the specified process is ended.
1686 >>>>>>> origin/release/1806.51:bpmn/MSOCommonBPMN/src/test/java/org/openecomp/mso/bpmn/common/WorkflowTest.java
1689 //TODO combine into 1
1690 private boolean isProcessEnded(String businessKey, String processName) {
1691 HistoricProcessInstance processInstance = historyService
1692 .createHistoricProcessInstanceQuery().processInstanceBusinessKey(businessKey).processDefinitionName(processName).singleResult();
1693 return processInstance != null && processInstance.getEndTime() != null;
1697 * Gets a variable value from a historical process instance. The business key must be unique.
1699 * @param businessKey the process business key
1700 * @param variableName the variable name
1701 * @return the variable value or null if the variable does not exist
1703 protected Object getVariableFromHistory(String businessKey, String variableName) {
1705 HistoricProcessInstance processInstance = historyService
1706 .createHistoricProcessInstanceQuery().processInstanceBusinessKey(businessKey).singleResult();
1708 if (processInstance == null) {
1712 HistoricVariableInstance v = historyService
1713 .createHistoricVariableInstanceQuery().processInstanceId(processInstance.getId())
1714 .variableName(variableName).singleResult();
1715 return v == null ? null : v.getValue();
1716 } catch (Exception e) {
1717 msoLogger.debug("Error retrieving variable " + variableName +
1718 " from historical process with business key " + businessKey + ": " + e);
1724 * Gets a variable value from a process instance based on businessKey and process name.
1725 * Must be used when multiple instances exist with the same business key such as when
1726 * business key is passed to subflows or shared across multiple processes. This method
1727 * can obtain variables from mainflows and from subflows.
1729 * @param businessKey the process business key
1730 * @param processName the process definition name
1731 * @param variableName the variable name
1732 * @return the variable value or null if the variable does not exist
1735 protected Object getVariableFromHistory(String businessKey, String processName, String variableName){
1737 HistoricProcessInstance processInstance = historyService.createHistoricProcessInstanceQuery().processInstanceBusinessKey(businessKey).processDefinitionName(processName)
1740 if(processInstance == null){
1743 HistoricVariableInstance variable = historyService.createHistoricVariableInstanceQuery().processInstanceId(processInstance.getId()).variableName(variableName).singleResult();
1745 return variable == null ? null : variable.getValue();
1746 }catch(ProcessEngineException e){
1747 msoLogger.debug("Multiple proccess instances exist with process name " + processName + " and business key " + businessKey + ". Must pass instance index as a parameter.");
1749 }catch(Exception e){
1750 msoLogger.debug("Error retrieving variable " + variableName + " from historical process for process " + processName + " with business key " + businessKey + ": " + e);
1756 * Gets the value of a process variable from x instance of y process. Must be used when
1757 * multiple instances exist with the same business key AND process name. This method
1758 * shall be used primarily for obtaining subflow variables when the business key is
1759 * passed to the subflow AND the subflow is called multiple times in a given flow.
1761 * @param businessKey the process business key
1762 * @param processName the name of the subflow that contains the variable
1763 * @param variableName the variable name
1764 * @param processInstanceIndex the instance in which the subprocess was called
1765 * @return the variable value or null if the variable does not exist
1768 protected Object getVariableFromHistory(String businessKey, int subflowInstanceIndex, String processName, String variableName){
1770 List<HistoricProcessInstance> processInstanceList = historyService.createHistoricProcessInstanceQuery().processInstanceBusinessKey(businessKey).processDefinitionName(processName)
1773 if(processInstanceList == null){
1776 processInstanceList.sort((m1, m2) -> m1.getStartTime().compareTo(m2.getStartTime()));
1778 HistoricProcessInstance processInstance = processInstanceList.get(subflowInstanceIndex);
1779 HistoricVariableInstance variable = historyService.createHistoricVariableInstanceQuery().processInstanceId(processInstance.getId())
1780 .variableName(variableName).singleResult();
1782 return variable == null ? null : variable.getValue();
1783 }catch(Exception e) {
1784 msoLogger.debug("Error retrieving variable " + variableName + " from historical process for process " + processName + " with business key " + businessKey + ": " + e);
1791 * Gets the value of a subflow variable from the specified subflow's
1792 * historical process instance.
1794 * DEPRECATED - Use method getVariableFromHistory(businessKey, processName, variableName) instead
1796 * @param subflowName - the name of the subflow that contains the variable
1797 * @param variableName the variable name
1799 * @return the variable value, or null if the variable could not be obtained
1803 protected Object getVariableFromSubflowHistory(String subflowName, String variableName) {
1805 List<HistoricProcessInstance> processInstanceList = historyService
1806 .createHistoricProcessInstanceQuery().processDefinitionName(subflowName).list();
1808 if (processInstanceList == null) {
1812 processInstanceList.sort((m1, m2) -> m1.getStartTime().compareTo(m2.getStartTime()));
1814 HistoricProcessInstance processInstance = processInstanceList.get(0);
1816 HistoricVariableInstance v = historyService
1817 .createHistoricVariableInstanceQuery().processInstanceId(processInstance.getId())
1818 .variableName(variableName).singleResult();
1819 return v == null ? null : v.getValue();
1820 } catch (Exception e) {
1821 msoLogger.debug("Error retrieving variable " + variableName +
1822 " from sub flow: " + subflowName + ", Exception is: " + e);
1828 * Gets the value of a subflow variable from the subflow's
1829 * historical process x instance.
1831 * DEPRECATED: Use method getVariableFromHistory(businessKey, processInstanceIndex, processName, variableName) instead
1833 * @param subflowName - the name of the subflow that contains the variable
1834 * @param variableName the variable name
1835 * @param subflowInstanceIndex - the instance of the subflow (use when same subflow is called more than once from mainflow)
1837 * @return the variable value, or null if the variable could not be obtained
1840 protected Object getVariableFromSubflowHistory(int subflowInstanceIndex, String subflowName, String variableName) {
1842 List<HistoricProcessInstance> processInstanceList = historyService.createHistoricProcessInstanceQuery().processDefinitionName(subflowName).list();
1844 if (processInstanceList == null) {
1848 processInstanceList.sort((m1, m2) -> m1.getStartTime().compareTo(m2.getStartTime()));
1850 HistoricProcessInstance processInstance = processInstanceList.get(subflowInstanceIndex);
1852 HistoricVariableInstance v = historyService.createHistoricVariableInstanceQuery().processInstanceId(processInstance.getId())
1853 .variableName(variableName).singleResult();
1854 return v == null ? null : v.getValue();
1855 } catch (Exception e) {
1856 msoLogger.debug("Error retrieving variable " + variableName +
1857 " from " + subflowInstanceIndex + " instance index of sub flow: " + subflowName + ", Exception is: " + e);
1863 * Extracts text from an XML element. This method is not namespace aware
1864 * (namespaces are ignored). The first matching element is selected.
1865 * @param xml the XML document or fragment
1866 * @param tag the desired element, e.g. "<name>"
1867 * @return the element text, or null if the element was not found
1869 protected String getXMLTextElement(String xml, String tag) {
1870 xml = removeXMLNamespaces(xml);
1872 if (!tag.startsWith("<")) {
1873 tag = "<" + tag + ">";
1876 int start = xml.indexOf(tag);
1882 int end = xml.indexOf('<', start + tag.length());
1888 return xml.substring(start + tag.length(), end);
1892 * Removes namespace definitions and prefixes from XML, if any.
1894 private String removeXMLNamespaces(String xml) {
1895 // remove xmlns declaration
1896 xml = xml.replaceAll("xmlns.*?(\"|\').*?(\"|\')", "");
1898 // remove opening tag prefix
1899 xml = xml.replaceAll("(<)(\\w+:)(.*?>)", "$1$3");
1901 // remove closing tags prefix
1902 xml = xml.replaceAll("(</)(\\w+:)(.*?>)", "$1$3");
1904 // remove extra spaces left when xmlns declarations are removed
1905 xml = xml.replaceAll("\\s+>", ">");
1911 * Asserts that two XML documents are semantically equivalent. Differences
1912 * in whitespace or in namespace usage do not affect the comparison.
1913 * @param expected the expected XML
1914 * @param actual the XML to test
1915 * @throws SAXException
1916 * @throws IOException
1918 public static void assertXMLEquals(String expected, String actual)
1919 throws SAXException, IOException {
1920 XMLUnit.setIgnoreWhitespace(true);
1921 XMLUnit.setIgnoreAttributeOrder(true);
1922 DetailedDiff diff = new DetailedDiff(XMLUnit.compareXML(expected, actual));
1923 List<?> allDifferences = diff.getAllDifferences();
1924 assertEquals("Differences found: " + diff.toString(), 0, allDifferences.size());
1928 * A test implementation of AsynchronousResponse.
1930 public class TestAsyncResponse {
1931 Response response = null;
1936 public synchronized void setResponse(Response response) {
1937 this.response = response;
1941 * Gets the response.
1942 * @return the response, or null if none has been produced yet
1944 public synchronized Response getResponse() {
1950 * An object that contains callback data for a "program".
1952 public class CallbackSet {
1953 private final Map<String, CallbackData> map = new HashMap<>();
1956 * Add untyped callback data to the set.
1957 * @param action the action with which the data is associated
1958 * @param content the callback data
1960 public void put(String action, String content) {
1961 map.put(action, new CallbackData(null, null, content));
1965 * Add callback data to the set.
1966 * @param action the action with which the data is associated
1967 * @param messageType the callback message type
1968 * @param content the callback data
1970 public void put(String action, String messageType, String content) {
1971 map.put(action, new CallbackData(null, messageType, content));
1975 * Add callback data to the set.
1976 * @param action the action with which the data is associated
1977 * @param contentType the callback HTTP content type
1978 * @param messageType the callback message type
1979 * @param content the callback data
1981 public void put(String action, String contentType, String messageType, String content) {
1982 map.put(action, new CallbackData(contentType, messageType, content));
1986 * Retrieve callback data from the set.
1987 * @param action the action with which the data is associated
1988 * @return the callback data, or null if there is none for the specified operation
1990 public CallbackData get(String action) {
1991 return map.get(action);
1996 * Represents a callback data item.
1998 public class CallbackData {
1999 private final String contentType;
2000 private final String messageType;
2001 private final String content;
2005 * @param contentType the HTTP content type (optional)
2006 * @param messageType the callback message type (optional)
2007 * @param content the content
2009 public CallbackData(String contentType, String messageType, String content) {
2010 this.contentType = contentType;
2011 this.messageType = messageType;
2012 this.content = content;
2016 * Gets the callback HTTP content type, possibly null.
2018 public String getContentType() {
2023 * Gets the callback message type, possibly null.
2025 public String getMessageType() {
2030 * Gets the callback content.
2032 public String getContent() {
2038 * A tool for evaluating XPath expressions.
2040 protected class XPathTool {
2041 private final DocumentBuilderFactory factory;
2042 private final SimpleNamespaceContext context = new SimpleNamespaceContext();
2043 private final XPath xpath = XPathFactory.newInstance().newXPath();
2044 private String xml = null;
2045 private Document doc = null;
2050 public XPathTool() {
2051 factory = DocumentBuilderFactory.newInstance();
2052 factory.setNamespaceAware(true);
2053 xpath.setNamespaceContext(context);
2058 * @param prefix the namespace prefix
2059 * @param uri the namespace uri
2061 public synchronized void addNamespace(String prefix, String uri) {
2062 context.add(prefix, uri);
2066 * Sets the XML content to be operated on.
2067 * @param xml the XML content
2069 public synchronized void setXML(String xml) {
2075 * Returns the document object.
2076 * @return the document object, or null if XML has not been set
2077 * @throws SAXException
2078 * @throws IOException
2079 * @throws ParserConfigurationException
2081 public synchronized Document getDocument()
2082 throws ParserConfigurationException, IOException, SAXException {
2092 * Evaluates the specified XPath expression and returns a string result.
2093 * This method throws exceptions on error.
2094 * @param expression the expression
2095 * @return the result object
2096 * @throws ParserConfigurationException
2097 * @throws IOException
2098 * @throws SAXException
2099 * @throws XPathExpressionException on error
2101 public synchronized String evaluate(String expression)
2102 throws ParserConfigurationException, SAXException,
2103 IOException, XPathExpressionException {
2104 return (String) evaluate(expression, XPathConstants.STRING);
2108 * Evaluates the specified XPath expression.
2109 * This method throws exceptions on error.
2110 * @param expression the expression
2111 * @param returnType the return type
2112 * @return the result object
2113 * @throws ParserConfigurationException
2114 * @throws IOException
2115 * @throws SAXException
2116 * @throws XPathExpressionException on error
2118 public synchronized Object evaluate(String expression, QName returnType)
2119 throws ParserConfigurationException, SAXException,
2120 IOException, XPathExpressionException {
2123 XPathExpression expr = xpath.compile(expression);
2124 return expr.evaluate(doc, returnType);
2128 * Private helper method that builds the document object.
2129 * Assumes the calling method is synchronized.
2130 * @throws ParserConfigurationException
2131 * @throws IOException
2132 * @throws SAXException
2134 private void buildDocument() throws ParserConfigurationException,
2135 IOException, SAXException {
2138 throw new IOException("XML input is null");
2141 DocumentBuilder builder = factory.newDocumentBuilder();
2142 InputSource source = new InputSource(new StringReader(xml));
2143 doc = builder.parse(source);
2149 * A NamespaceContext class based on a Map.
2151 private class SimpleNamespaceContext implements NamespaceContext {
2152 private Map<String, String> prefixMap = new HashMap<>();
2153 private Map<String, String> uriMap = new HashMap<>();
2155 public synchronized void add(String prefix, String uri) {
2156 prefixMap.put(prefix, uri);
2157 uriMap.put(uri, prefix);
2161 public synchronized String getNamespaceURI(String prefix) {
2162 return prefixMap.get(prefix);
2166 public Iterator<String> getPrefixes(String uri) {
2167 List<String> list = new ArrayList<>();
2168 String prefix = uriMap.get(uri);
2169 if (prefix != null) {
2172 return list.iterator();
2176 public String getPrefix(String uri) {
2177 return uriMap.get(uri);
2182 * A VnfNotify XPathTool.
2184 protected class VnfNotifyXPathTool extends XPathTool {
2185 public VnfNotifyXPathTool() {
2186 addNamespace("tns", "http://org.onap.so/vnfNotify");
2191 * Helper class to make it easier to create this type.
2193 private static class CreateVnfNotificationOutputs
2194 extends CreateVnfNotification.Outputs {
2195 public void add(String key, String value) {
2196 Entry entry = new Entry();
2198 entry.setValue(value);
2199 getEntry().add(entry);
2204 * Helper class to make it easier to create this type.
2206 private static class UpdateVnfNotificationOutputs
2207 extends UpdateVnfNotification.Outputs {
2208 public void add(String key, String value) {
2209 Entry entry = new Entry();
2211 entry.setValue(value);
2212 getEntry().add(entry);