io.github.microcks.util.soapui.SoapUIProjectImporter Maven / Gradle / Ivy
The newest version!
/*
* Copyright The Microcks Authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.github.microcks.util.soapui;
import io.github.microcks.domain.Exchange;
import io.github.microcks.domain.Header;
import io.github.microcks.domain.Operation;
import io.github.microcks.domain.Parameter;
import io.github.microcks.domain.Request;
import io.github.microcks.domain.RequestResponsePair;
import io.github.microcks.domain.Resource;
import io.github.microcks.domain.ResourceType;
import io.github.microcks.domain.Response;
import io.github.microcks.domain.Service;
import io.github.microcks.domain.ServiceType;
import io.github.microcks.util.DispatchCriteriaHelper;
import io.github.microcks.util.DispatchStyles;
import io.github.microcks.util.MalformedXmlException;
import io.github.microcks.util.MockRepositoryImportException;
import io.github.microcks.util.MockRepositoryImporter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.Element;
import org.xml.sax.InputSource;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.xpath.XPathExpression;
import javax.xml.xpath.XPathExpressionException;
import java.io.IOException;
import java.io.StringReader;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;
import static io.github.microcks.util.XmlUtil.WSDL_NS;
import static io.github.microcks.util.XmlUtil.getDirectChildren;
import static io.github.microcks.util.XmlUtil.getUniqueDirectChild;
import static io.github.microcks.util.soapui.SoapUIProjectParserUtils.getConfigDirectChildren;
import static io.github.microcks.util.soapui.SoapUIProjectParserUtils.getConfigUniqueDirectChild;
import static io.github.microcks.util.soapui.SoapUIProjectParserUtils.hasConfigDirectChild;
/**
* Implement of MockRepositoryImporter that uses a SoapUI project for building domain objects.
* @author laurent
*/
public class SoapUIProjectImporter implements MockRepositoryImporter {
/** A simple logger for diagnostic messages. */
private static Logger log = LoggerFactory.getLogger(SoapUIProjectImporter.class);
/** SoapUI project property that references service version property. */
public static final String SERVICE_VERSION_PROPERTY = "version";
protected static final String NAME_ATTRIBUTE = "name";
protected static final String ELEMENT_ATTRIBUTE = "element";
protected static final String MOCK_SERVICE_TAG = "mockService";
protected static final String REST_MOCK_SERVICE_TAG = "restMockService";
protected static final String MOCK_OPERATION_TAG = "mockOperation";
protected static final String REST_MOCK_ACTION_TAG = "restMockAction";
protected static final String REQUEST_TAG = "request";
protected static final String RESPONSE_TAG = "response";
private String projectContent;
private DocumentBuilder documentBuilder;
private Element projectElement;
private Element serviceInterface;
private Map interfaces = new HashMap<>();
/**
* Build a new importer.
* @param projectFilePath The path to local SoapUI project file
* @throws IOException if project file cannot be found
*/
public SoapUIProjectImporter(String projectFilePath) throws IOException {
try {
// Read project content as string.
byte[] projectBytes = Files.readAllBytes(Paths.get(projectFilePath));
projectContent = new String(projectBytes, StandardCharsets.UTF_8);
// Then parse it to get DOM root Element.
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
factory.setNamespaceAware(true);
documentBuilder = factory.newDocumentBuilder();
projectElement = documentBuilder.parse(new InputSource(new StringReader(projectContent))).getDocumentElement();
} catch (Exception e) {
log.error("Exception while parsing SoapUI file " + projectFilePath, e);
throw new IOException("SoapUI project file parsing error");
}
}
@Override
public List getServiceDefinitions() throws MockRepositoryImportException {
List result = new ArrayList<>();
List interfaceNodes = getConfigDirectChildren(projectElement, "interface");
for (Element interfaceNode : interfaceNodes) {
// Filter complete interface definition with name as attribute.
if (interfaceNode.getAttribute(NAME_ATTRIBUTE) != null) {
log.info("Found a service interface named: {}", interfaceNode.getAttribute(NAME_ATTRIBUTE));
interfaces.put(interfaceNode.getAttribute(NAME_ATTRIBUTE), interfaceNode);
serviceInterface = interfaceNode;
}
}
// Try loading definitions from Soap mock services.
List mockServices = getConfigDirectChildren(projectElement, MOCK_SERVICE_TAG);
if (!mockServices.isEmpty()) {
result.addAll(getSoapServicesDefinitions(mockServices));
}
// Then try loading from Rest mock services.
List restMockServices = getConfigDirectChildren(projectElement, REST_MOCK_SERVICE_TAG);
if (!restMockServices.isEmpty()) {
result.addAll(getRestServicesDefinitions(restMockServices));
}
return result;
}
private List getSoapServicesDefinitions(List mockServices) throws MockRepositoryImportException {
List result = new ArrayList<>();
try {
for (Element mockService : mockServices) {
// Build a new Service.
Service service = new Service();
service.setName(mockService.getAttribute(NAME_ATTRIBUTE));
service.setType(ServiceType.SOAP_HTTP);
// Check version property that is mandatory.
Element properties = getConfigUniqueDirectChild(mockService, "properties");
service.setVersion(extractVersion(properties));
List mockOperations = getConfigDirectChildren(mockService, MOCK_OPERATION_TAG);
for (Element mockOperation : mockOperations) {
Element interfaceElement = interfaces.get(mockOperation.getAttribute("interface"));
if (interfaceElement != null) {
log.info("Got matching service interface");
String bindingQName = interfaceElement.getAttribute("bindingName");
service.setXmlNS(extractNSFromQName(bindingQName));
}
// Build a new operation from mockOperation.
Operation operation = new Operation();
operation.setName(mockOperation.getAttribute(NAME_ATTRIBUTE));
Element interfaceOperation = getInterfaceOperation(interfaceElement, operation.getName());
operation.setAction(interfaceOperation.getAttribute("action"));
try {
completeOperationPartsFromWsdl(interfaceElement, operation);
} catch (Exception e) {
// Fallback to input name as a (mostly?) safe default.
log.warn(
"Was not able to extract element names for input/output payload from WSDL. Defaulting to input and output names.");
} finally {
if (operation.getInputName() == null) {
operation.setInputName(interfaceOperation.getAttribute("inputName"));
}
if (operation.getOutputName() == null) {
operation.setOutputName(interfaceOperation.getAttribute("outputName"));
}
}
Element dispatchStyle = getConfigUniqueDirectChild(mockOperation, "dispatchStyle");
operation.setDispatcher(dispatchStyle.getTextContent());
if (DispatchStyles.QUERY_MATCH.equals(operation.getDispatcher())) {
// XPath matching rules are under dispatchConfig.query, consider 1st item only.
Element dispatchConfig = getConfigUniqueDirectChild(mockOperation, "dispatchConfig");
Element firstQuery = getConfigDirectChildren(dispatchConfig, "query").get(0);
operation.setDispatcherRules(getConfigUniqueDirectChild(firstQuery, "query").getTextContent());
} else if (DispatchStyles.SCRIPT.equals(operation.getDispatcher())) {
// Groovy script is located into dispatchPath element.
operation
.setDispatcherRules(getConfigUniqueDirectChild(mockOperation, "dispatchPath").getTextContent());
}
service.addOperation(operation);
}
result.add(service);
}
} catch (MalformedXmlException mspe) {
log.error("Your SoapUI Project seems to be malformed: {}", mspe.getMessage(), mspe);
throw new MockRepositoryImportException("Your SoapUI Project seems to be malformed: " + mspe.getMessage(),
mspe);
}
return result;
}
private void completeOperationPartsFromWsdl(Element interfaceElement, Operation operation) throws Exception {
Element definitionCache = getConfigUniqueDirectChild(interfaceElement, "definitionCache");
List parts = getConfigDirectChildren(definitionCache, "part");
Element wsdlPart = parts.get(0);
Element wsdlContent = getConfigUniqueDirectChild(wsdlPart, "content");
String wsdlTextContent = wsdlContent.getTextContent();
Element wsdlDoc = documentBuilder.parse(new InputSource(new StringReader(wsdlTextContent))).getDocumentElement();
Element binding = getUniqueDirectChild(wsdlDoc, WSDL_NS, "binding");
List wsdlOperations = getDirectChildren(binding, WSDL_NS, "operation");
for (Element wsdlOperation : wsdlOperations) {
if (operation.getName().equals(wsdlOperation.getAttribute(NAME_ATTRIBUTE))) {
Element input = getUniqueDirectChild(wsdlOperation, WSDL_NS, "input");
Element output = getUniqueDirectChild(wsdlOperation, WSDL_NS, "output");
String inputName = input.getAttribute(NAME_ATTRIBUTE);
String outputName = output.getAttribute(NAME_ATTRIBUTE);
List messages = getDirectChildren(wsdlDoc, WSDL_NS, "message");
Optional inputMsg = messages.stream().filter(m -> inputName.equals(m.getAttribute(NAME_ATTRIBUTE)))
.findFirst();
Optional outputMsg = messages.stream()
.filter(m -> outputName.equals(m.getAttribute(NAME_ATTRIBUTE))).findFirst();
if (inputMsg.isPresent()) {
Element firstPart = getDirectChildren(inputMsg.get(), WSDL_NS, "part").get(0);
String localTag = firstPart.getAttribute(ELEMENT_ATTRIBUTE)
.substring(firstPart.getAttribute(ELEMENT_ATTRIBUTE).indexOf(":") + 1);
operation.setInputName(localTag);
}
if (outputMsg.isPresent()) {
Element firstPart = getDirectChildren(outputMsg.get(), WSDL_NS, "part").get(0);
String localTag = firstPart.getAttribute(ELEMENT_ATTRIBUTE)
.substring(firstPart.getAttribute(ELEMENT_ATTRIBUTE).indexOf(":") + 1);
operation.setOutputName(localTag);
}
}
}
}
private List getRestServicesDefinitions(List restMockServices)
throws MockRepositoryImportException {
List result = new ArrayList<>();
try {
for (Element mockService : restMockServices) {
// Build a new Service.
Service service = new Service();
service.setName(mockService.getAttribute(NAME_ATTRIBUTE));
service.setType(ServiceType.REST);
// Check version property that is mandatory.
Element properties = getConfigUniqueDirectChild(mockService, "properties");
service.setVersion(extractVersion(properties));
// Actions corresponding to same operations may be defined multiple times in SoapUI
// with different resourcePaths. We have to track them to complete them in second step.
Map collectedOperations = new HashMap<>();
List mockOperations = getConfigDirectChildren(mockService, REST_MOCK_ACTION_TAG);
for (Element mockOperation : mockOperations) {
// Check already found operation.
Operation operation = collectedOperations.get(mockOperation.getAttribute(NAME_ATTRIBUTE));
if (operation == null) {
// Build a new operation from mockRestAction.
operation = new Operation();
operation.setName(mockOperation.getAttribute(NAME_ATTRIBUTE));
operation.setMethod(mockOperation.getAttribute("method"));
Element dispatchStyle = getConfigUniqueDirectChild(mockOperation, "dispatchStyle");
operation.setDispatcher(dispatchStyle.getTextContent());
if (DispatchStyles.SEQUENCE.equals(operation.getDispatcher())) {
// Extract simple dispatcher rules from operation name.
operation
.setDispatcherRules(DispatchCriteriaHelper.extractPartsFromURIPattern(operation.getName()));
} else if (DispatchStyles.SCRIPT.equals(operation.getDispatcher())) {
// Groovy script is located into dispatchPath element.
operation.setDispatcherRules(
getConfigUniqueDirectChild(mockOperation, "dispatchPath").getTextContent());
}
service.addOperation(operation);
}
// Add this configuration resource path.
operation.addResourcePath(mockOperation.getAttribute("resourcePath"));
collectedOperations.put(mockOperation.getAttribute("name"), operation);
}
result.add(service);
}
} catch (MalformedXmlException mspe) {
log.error("Your SoapUI Project seems to be malformed: {}", mspe.getMessage(), mspe);
throw new MockRepositoryImportException("Your SoapUI Project seems to be malformed: " + mspe.getMessage(),
mspe);
}
return result;
}
@Override
public List getResourceDefinitions(Service service) {
List results = new ArrayList<>();
// First record the project itself as an artifact.
Resource projectResource = new Resource();
projectResource.setName(service.getName() + "-" + service.getVersion() + ".xml");
projectResource.setType(ResourceType.SOAP_UI_PROJECT);
projectResource.setContent(projectContent);
results.add(projectResource);
try {
Element definitionCache = getConfigUniqueDirectChild(serviceInterface, "definitionCache");
List parts = getConfigDirectChildren(definitionCache, "part");
if (!parts.isEmpty()) {
Element wsdlPart = parts.get(0);
Element wsdlContent = getConfigUniqueDirectChild(wsdlPart, "content");
String wsdlTextContent = wsdlContent.getTextContent();
for (int i = 1; i < parts.size(); i++) {
Element xsdPart = parts.get(i);
String xsdUrl = getConfigUniqueDirectChild(xsdPart, "url").getTextContent().trim();
String xsdName = xsdUrl.substring(xsdUrl.lastIndexOf('/') + 1);
// Try also Windows style path separators.
if (xsdUrl.contains("\\")) {
xsdName = xsdUrl.substring(xsdUrl.lastIndexOf("\\") + 1);
}
String xsdContent = getConfigUniqueDirectChild(xsdPart, "content").getTextContent();
Resource xsdResource = new Resource();
xsdResource.setName(xsdName);
xsdResource.setType(ResourceType.XSD);
xsdResource.setContent(xsdContent);
results.add(xsdResource);
// URL references within WSDL must be replaced by their local counterpart.
wsdlTextContent = wsdlTextContent.replace(xsdUrl, "./" + xsdName);
// TODO: have a in-depth review on how xsd are actually resolved (and should probably be fixed)
// wsdlTextContent = wsdlTextContent.replaceAll("schemaLocation=\"(.*)\\/(" + xsdName + ")", "schemaLocation=\"./" + xsdName + "\"");
}
Resource wsdlResource = new Resource();
wsdlResource.setName(service.getName() + "-" + service.getVersion() + ".wsdl");
wsdlResource.setType(ResourceType.WSDL);
wsdlResource.setContent(wsdlTextContent);
results.add(wsdlResource);
}
} catch (MalformedXmlException mxe) {
log.warn("Got a MalformedXmlException while trying to extract WSDL and XSD: {}", mxe.getMessage());
log.warn("Just failing silently as it's not a critical stuff in SoapUI implementation");
}
return results;
}
@Override
public List getMessageDefinitions(Service service, Operation operation)
throws MockRepositoryImportException {
List results = new ArrayList<>();
if (ServiceType.SOAP_HTTP == service.getType()) {
results.addAll(getSoapMessageDefinitions(service, operation));
} else if (ServiceType.REST == service.getType()) {
results.addAll(getRestMessageDefinitions(service, operation));
}
return results;
}
private List getSoapMessageDefinitions(Service service, Operation operation)
throws MockRepositoryImportException {
Map result = new HashMap<>();
try {
List mockServices = getConfigDirectChildren(projectElement, MOCK_SERVICE_TAG);
for (Element mockService : mockServices) {
// Find the appropriate mock service.
if (service.getName().equals(mockService.getAttribute(NAME_ATTRIBUTE))) {
List mockOperations = getConfigDirectChildren(mockService, MOCK_OPERATION_TAG);
for (Element mockOperation : mockOperations) {
// Find the appropriate mock service operation.
if (operation.getName().equals(mockOperation.getAttribute("operation"))) {
// Collect available test requests for this operation.
Map availableRequests = collectTestStepsRequests(operation);
// Then filter only those that are candidates to mock response matching.
List candidateRequests = new ArrayList<>();
List mockResponses = getConfigDirectChildren(mockOperation, RESPONSE_TAG);
for (Element mockResponse : mockResponses) {
String responseName = mockResponse.getAttribute(NAME_ATTRIBUTE);
Element matchingRequest = availableRequests.get(responseName);
if (matchingRequest == null) {
matchingRequest = availableRequests.get(responseName + " Request");
}
if (matchingRequest == null && responseName.contains("Response")) {
matchingRequest = availableRequests.get(responseName.replace("Response", "Request"));
}
if (matchingRequest == null) {
log.warn("No request found for response '{}' into SoapUI project '{}'", responseName,
projectElement.getAttribute("name"));
continue;
}
candidateRequests.add(matchingRequest);
}
if (DispatchStyles.QUERY_MATCH.equals(operation.getDispatcher())) {
// Browse candidates and apply query dispatcher criterion to find corresponding response.
try {
XPathExpression xpath = initializeXPathMatcher(operation);
Map matchToResponseMap = buildQueryMatchDispatchCriteriaToResponseMap(
mockOperation);
for (Element candidateRequest : candidateRequests) {
// Evaluate matcher against request and get name of corresponding response.
String requestContent = getConfigUniqueDirectChild(candidateRequest, REQUEST_TAG)
.getTextContent();
String dispatchCriteria = xpath
.evaluate(new InputSource(new StringReader(requestContent)));
String correspondingResponse = matchToResponseMap.get(dispatchCriteria);
Element matchingResponse = getMockResponseByName(mockOperation, correspondingResponse);
if (matchingResponse != null) {
// Build response from MockResponse and response from matching one.
Response response = buildResponse(matchingResponse, dispatchCriteria);
Request request = buildRequest(candidateRequest);
result.put(request, response);
}
}
} catch (XPathExpressionException e) {
throw new RuntimeException(e);
}
} else if (DispatchStyles.SCRIPT.equals(operation.getDispatcher())) {
for (Element candidateRequest : candidateRequests) {
Element mockResponse = getMockResponseByName(mockOperation,
candidateRequest.getAttribute(NAME_ATTRIBUTE));
if (mockResponse == null
&& candidateRequest.getAttribute(NAME_ATTRIBUTE).contains("Request")) {
mockResponse = getMockResponseByName(mockOperation,
candidateRequest.getAttribute(NAME_ATTRIBUTE).replace(" Request", " Response"));
}
if (mockResponse == null) {
log.warn("No response found for request {} into SoapUI project {}",
candidateRequest.getAttribute(NAME_ATTRIBUTE),
projectElement.getAttribute(NAME_ATTRIBUTE));
continue;
}
// Build response from MockResponse and response from matching one.
Response response = buildResponse(mockResponse, mockResponse.getAttribute(NAME_ATTRIBUTE));
Request request = buildRequest(candidateRequest);
result.put(request, response);
}
} else if (DispatchStyles.RANDOM.equals(operation.getDispatcher())) {
{
if (availableRequests.isEmpty()) {
log.warn(
"A request is mandatory even for a RANDOM dispatch. Operation {} into SoapUI project {}",
operation.getName(), projectElement.getAttribute(NAME_ATTRIBUTE));
} else {
// Use the first one for all the responses
Element mockRequest = availableRequests.values().iterator().next();
for (Element mockResponse : mockResponses) {
// Build response from MockResponse and response from matching one.
Response response = buildResponse(mockResponse, DispatchStyles.RANDOM);
Request request = buildRequest(mockRequest);
request.setName(operation.getName());
result.put(request, response);
}
}
}
}
break;
}
}
break;
}
}
} catch (Throwable t) {
throw new MockRepositoryImportException(t.getMessage());
}
// Adapt map to list of Exchanges.
return result.entrySet().stream().map(entry -> new RequestResponsePair(entry.getKey(), entry.getValue()))
.collect(Collectors.toList());
}
private List getRestMessageDefinitions(Service service, Operation operation)
throws MockRepositoryImportException {
Map result = new HashMap<>();
try {
List mockServices = getConfigDirectChildren(projectElement, REST_MOCK_SERVICE_TAG);
for (Element mockService : mockServices) {
// Find the appropriate mock service.
if (service.getName().equals(mockService.getAttribute(NAME_ATTRIBUTE))) {
List mockOperations = getConfigDirectChildren(mockService, REST_MOCK_ACTION_TAG);
for (Element mockOperation : mockOperations) {
// Find the appropriate mock service operation.
if (operation.getName().equals(mockOperation.getAttribute(NAME_ATTRIBUTE))) {
// Collect available test requests for this operation.
Map availableRequests = collectTestStepsRestRequests(operation);
// Collection also mock responses that are sparsly dispatched under mockRestActions having the name same.
List mockResponses = getMockRestResponses(mockService, operation);
// Then filter only those that are matching with a mock response.
Map requestToResponses = new HashMap<>();
for (Element mockResponse : mockResponses) {
String responseName = mockResponse.getAttribute(NAME_ATTRIBUTE);
Element matchingRequest = availableRequests.get(responseName);
if (matchingRequest == null) {
matchingRequest = availableRequests.get(responseName + " Request");
}
if (matchingRequest == null && responseName.contains("Response")) {
matchingRequest = availableRequests.get(responseName.replace("Response", "Request"));
}
if (matchingRequest == null) {
log.warn("No request found for response '{}' into SoapUI project '{}'", responseName,
projectElement.getAttribute("name"));
continue;
}
requestToResponses.put(matchingRequest, mockResponse);
}
for (Map.Entry entry : requestToResponses.entrySet()) {
String dispatchCriteria = null;
if (DispatchStyles.SEQUENCE.equals(operation.getDispatcher())) {
// Build a dispatch criteria from operation name projected onto resourcePath pattern
// eg. /deployment/byComponent/{component}/{version}.json => /deployment/byComponent/testREST/1.2.json
// for producing /component=testREST/version=1.2
// resourcePath is actually available in restMockAction wrapping response. Navigate to parent.
String resourcePath = ((Element) entry.getValue().getParentNode())
.getAttribute("resourcePath");
dispatchCriteria = DispatchCriteriaHelper.extractFromURIPattern(
operation.getDispatcherRules(), operation.getName(), resourcePath);
} else if (DispatchStyles.SCRIPT.equals(operation.getDispatcher())) {
// Build a dispatch criteria that is equal to response name (that script evaluation should return...)
dispatchCriteria = entry.getValue().getAttribute(NAME_ATTRIBUTE);
}
Response response = buildResponse(entry.getValue(), dispatchCriteria);
Request request = buildRequest(entry.getKey());
result.put(request, response);
}
break;
}
}
}
}
} catch (Throwable t) {
throw new MockRepositoryImportException(t.getMessage());
}
// Adapt map to list of Exchanges.
return result.entrySet().stream().map(entry -> new RequestResponsePair(entry.getKey(), entry.getValue()))
.collect(Collectors.toList());
}
private String extractNSFromQName(String qName) {
if (qName.startsWith("{") && qName.indexOf("}") > 1) {
return qName.substring(1, qName.indexOf("}"));
}
return qName;
}
/** Extract version from mockService properties. */
private String extractVersion(Element properties) throws MockRepositoryImportException, MalformedXmlException {
List propertyList = getConfigDirectChildren(properties, "property");
for (Element property : propertyList) {
Element propertyName = getConfigUniqueDirectChild(property, NAME_ATTRIBUTE);
Element propertyValue = getConfigUniqueDirectChild(property, "value");
if (SERVICE_VERSION_PROPERTY.equals(propertyName.getTextContent())) {
return propertyValue.getTextContent();
}
}
log.error("Version property is missing in Project properties");
throw new MockRepositoryImportException("Version property is missing in Project properties");
}
private Element getInterfaceOperation(Element serviceInterface, String operationName)
throws MockRepositoryImportException {
List operations = getConfigDirectChildren(serviceInterface, "operation");
for (Element operation : operations) {
if (operationName.equals(operation.getAttribute(NAME_ATTRIBUTE))) {
return operation;
}
}
log.error("Operation {} is missing into Service interface", operationName);
throw new MockRepositoryImportException("Operation " + operationName + " is missing into Service interface");
}
private Map collectTestStepsRequests(Operation operation) throws MalformedXmlException {
Map results = new HashMap<>();
List testSuites = getConfigDirectChildren(projectElement, "testSuite");
for (Element testSuite : testSuites) {
List testCases = getConfigDirectChildren(testSuite, "testCase");
for (Element testCase : testCases) {
List testSteps = getConfigDirectChildren(testCase, "testStep");
for (Element testStep : testSteps) {
Element config = getConfigUniqueDirectChild(testStep, "config");
String interfaceName = getConfigUniqueDirectChild(config, "interface").getTextContent();
String operationName = getConfigUniqueDirectChild(config, "operation").getTextContent();
if (operation.getName().equals(operationName)) {
results.put(testStep.getAttribute(NAME_ATTRIBUTE), getConfigUniqueDirectChild(config, REQUEST_TAG));
}
}
}
}
return results;
}
private Map collectTestStepsRestRequests(Operation operation) throws MalformedXmlException {
Map results = new HashMap<>();
List testSuites = getConfigDirectChildren(projectElement, "testSuite");
for (Element testSuite : testSuites) {
List testCases = getConfigDirectChildren(testSuite, "testCase");
for (Element testCase : testCases) {
List testSteps = getConfigDirectChildren(testCase, "testStep");
for (Element testStep : testSteps) {
Element config = getConfigUniqueDirectChild(testStep, "config");
String operationName = config.getAttribute("resourcePath");
if (operation.getName().equals(operationName)) {
results.put(testStep.getAttribute(NAME_ATTRIBUTE), getConfigUniqueDirectChild(config, "restRequest"));
}
}
}
}
return results;
}
private List getMockRestResponses(Element restMockService, Operation operation) {
List responses = new ArrayList<>();
List mockActions = getConfigDirectChildren(restMockService, REST_MOCK_ACTION_TAG);
for (Element mockAction : mockActions) {
if (operation.getName().equals(mockAction.getAttribute(NAME_ATTRIBUTE))) {
responses.addAll(getConfigDirectChildren(mockAction, RESPONSE_TAG));
}
}
return responses;
}
/** Build a XPathMatcher based on operation dispatcher rules. */
private XPathExpression initializeXPathMatcher(Operation operation) throws XPathExpressionException {
return SoapUIXPathBuilder.buildXPathMatcherFromRules(operation.getDispatcherRules());
}
private Map buildQueryMatchDispatchCriteriaToResponseMap(Element mockOperation)
throws MalformedXmlException {
Map matchResponseMap = new HashMap<>();
String dispatcher = getConfigUniqueDirectChild(mockOperation, "dispatchStyle").getTextContent();
if (DispatchStyles.QUERY_MATCH.equals(dispatcher)) {
Element dispatchConfig = getConfigUniqueDirectChild(mockOperation, "dispatchConfig");
List queries = SoapUIProjectParserUtils.getConfigDirectChildren(dispatchConfig, "query");
for (Element query : queries) {
String match = getConfigUniqueDirectChild(query, "match").getTextContent();
String response = getConfigUniqueDirectChild(query, RESPONSE_TAG).getTextContent();
matchResponseMap.put(match, response);
}
}
return matchResponseMap;
}
private Element getMockResponseByName(Element mockOperation, String responseName) {
List responses = getConfigDirectChildren(mockOperation, RESPONSE_TAG);
for (Element response : responses) {
if (responseName.equals(response.getAttribute(NAME_ATTRIBUTE))) {
return response;
}
}
return null;
}
private Response buildResponse(Element mockResponse, String dispatchCriteria)
throws MockRepositoryImportException, Exception {
Response response = new Response();
response.setName(mockResponse.getAttribute(NAME_ATTRIBUTE));
response.setContent(getConfigUniqueDirectChild(mockResponse, "responseContent").getTextContent());
response.setHeaders(buildHeaders(mockResponse));
response.setDispatchCriteria(dispatchCriteria);
response.setStatus(mockResponse.getAttribute("httpResponseStatus"));
if ("500".equals(response.getStatus())) {
response.setFault(true);
}
response.setMediaType(mockResponse.getAttribute("mediaType"));
return response;
}
private Request buildRequest(Element testRequest) throws MockRepositoryImportException, Exception {
Request request = new Request();
request.setName(testRequest.getAttribute(NAME_ATTRIBUTE));
request.setContent(getConfigUniqueDirectChild(testRequest, REQUEST_TAG).getTextContent());
request.setHeaders(buildHeaders(testRequest));
// Add query parameters only if presents.
if (hasConfigDirectChild(testRequest, "parameters")) {
List entries = getConfigDirectChildren(getConfigUniqueDirectChild(testRequest, "parameters"),
"entry");
for (Element entry : entries) {
Parameter param = new Parameter();
param.setName(entry.getAttribute("key"));
param.setValue(entry.getAttribute("value"));
request.addQueryParameter(param);
}
}
return request;
}
private Set buildHeaders(Element requestOrResponse) throws Exception {
Element settingsElt = getConfigUniqueDirectChild(requestOrResponse, "settings");
List settings = getConfigDirectChildren(settingsElt, "setting");
for (Element setting : settings) {
if (setting.getAttribute("id").contains("@request-headers")) {
// 2 possibilities here:
// 1) <xml-fragment xmlns:con="http://eviware.com/soapui/config">
// <con:entry key="Authorization" value="Basic YWRtaW46YWRtaW4="/>
// <con:entry key="x-userid" value="s026210"/>
// </xml-fragment>
// 2) <entry key="toto"
// value="tata" xmlns="http://eviware.com/soapui/config"/>
String headersContent = setting.getTextContent();
Element fragment = documentBuilder.parse(new InputSource(new StringReader(headersContent)))
.getDocumentElement();
Set headers = new HashSet<>();
if (headersContent.contains("xml-fragment")) {
List entries = getConfigDirectChildren(fragment, "entry");
for (Element entry : entries) {
Header header = new Header();
header.setName(entry.getAttribute("key"));
header.setValues(Set.of(entry.getAttribute("value")));
headers.add(header);
}
} else {
Header header = new Header();
header.setName(fragment.getAttribute("key"));
header.setValues(Set.of(fragment.getAttribute("value")));
headers.add(header);
}
return headers;
}
}
return null;
}
}