
io.github.microcks.util.soapui.SoapUIProjectImporter Maven / Gradle / Ivy
/*
* Licensed to Laurent Broudoux (the "Author") under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. Author licenses this
* file to you 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 com.eviware.soapui.config.DefintionPartConfig;
import com.eviware.soapui.config.RESTMockActionConfig;
import com.eviware.soapui.config.RESTMockResponseConfig;
import com.eviware.soapui.impl.rest.mock.RestMockResponse;
import com.eviware.soapui.impl.rest.mock.RestMockService;
import com.eviware.soapui.impl.rest.support.RestParamsPropertyHolder;
import com.eviware.soapui.impl.wsdl.WsdlInterface;
import com.eviware.soapui.impl.wsdl.WsdlOperation;
import com.eviware.soapui.impl.wsdl.WsdlProject;
import com.eviware.soapui.impl.wsdl.mock.WsdlMockOperation;
import com.eviware.soapui.impl.wsdl.mock.WsdlMockResponse;
import com.eviware.soapui.impl.wsdl.mock.WsdlMockService;
import com.eviware.soapui.impl.wsdl.mock.dispatch.MockOperationDispatcher;
import com.eviware.soapui.impl.wsdl.mock.dispatch.QueryMatchMockOperationDispatcher;
import com.eviware.soapui.impl.wsdl.mock.dispatch.ScriptMockOperationDispatcher;
import com.eviware.soapui.impl.wsdl.teststeps.RestTestRequest;
import com.eviware.soapui.impl.wsdl.teststeps.RestTestRequestStep;
import com.eviware.soapui.impl.wsdl.teststeps.WsdlTestRequest;
import com.eviware.soapui.impl.wsdl.teststeps.WsdlTestRequestStep;
import com.eviware.soapui.model.mock.MockOperation;
import com.eviware.soapui.model.mock.MockResponse;
import com.eviware.soapui.model.mock.MockService;
import com.eviware.soapui.model.testsuite.TestCase;
import com.eviware.soapui.model.testsuite.TestStep;
import com.eviware.soapui.model.testsuite.TestSuite;
import com.eviware.soapui.support.types.StringToStringsMap;
import io.github.microcks.util.DispatchCriteriaHelper;
import io.github.microcks.util.DispatchStyles;
import io.github.microcks.util.MockRepositoryImportException;
import io.github.microcks.util.MockRepositoryImporter;
import io.github.microcks.domain.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.xml.sax.InputSource;
import javax.xml.xpath.XPathExpression;
import javax.xml.xpath.XPathExpressionException;
import java.io.IOException;
import java.io.StringReader;
import java.util.*;
import java.util.stream.Collectors;
/**
* 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";
private WsdlProject project;
/**
* 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{
project = new WsdlProject(projectFilePath);
} 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<>();
// Add Soap and then Rest services definitions.
result.addAll(getSoapServiceDefinitions(project.getMockServiceList()));
result.addAll(getRestServiceDefinitions(project.getRestMockServiceList()));
return result;
}
@Override
public List getResourceDefinitions(Service service) {
List results = new ArrayList<>();
// For now, only available for Wsdl based projects having mocked interfaces.
WsdlMockService wsdlMockService = project.getMockServiceByName(service.getName());
if (wsdlMockService != null){
// Use only the fisrt interface of the mock service corresponding to service.
WsdlInterface wi = project.getMockServiceByName(service.getName()).getMockedInterfaces()[0];
List parts = wi.getConfig().getDefinitionCache().getPartList();
if (parts != null && parts.size() > 0){
// First part is always the wsdl definition, get its content as string.
String wsdlContent = parts.get(0).getContent().newCursor().getTextValue();
// Then browse the following one (XSD) and change relative path in imports.
for (int i=1; i getMessageDefinitions(Service service, Operation operation) throws MockRepositoryImportException {
// First try with a Soap Service mock...
MockService mockService = project.getMockServiceByName(service.getName());
if (mockService != null){
try {
return getSoapMessageDefinitions(mockService, operation);
} catch (XPathExpressionException xpe) {
log.error("Got a XPathExpressionException while retrieving soap messages", xpe);
throw new MockRepositoryImportException("XPathExpressionExcpetion while retrieving soap messages", xpe);
}
}
// ... then with a Rest Service mock.
RestMockService restMockService = project.getRestMockServiceByName(service.getName());
if (restMockService != null){
return getRestMessageDefinitions(restMockService, operation);
}
return new ArrayList();
}
/**
* Get the definitions of Soap Services from mock services.
*/
private List getSoapServiceDefinitions(List mockServices) throws MockRepositoryImportException {
List result = new ArrayList<>();
for (WsdlMockService wms : mockServices){
// First assume it's a Soap one.
Service service = new Service();
service.setName(wms.getName());
service.setType(ServiceType.SOAP_HTTP);
// Ensure we've got only one interface and extract its namespace.
WsdlInterface[] wi = wms.getMockedInterfaces();
if (wi == null || wi.length > 1){
// TODO Throw a typed exception here...
}
service.setXmlNS(wi[0].getBindingName().getNamespaceURI());
// Extract version from custom properties.
String version = wms.getPropertyValue(SERVICE_VERSION_PROPERTY);
if (version == null){
log.error("Version property is missing in Project properties");
throw new MockRepositoryImportException("Version property is missing in Project properties");
}
service.setVersion(version);
// Then build its operations.
service.setOperations(extractOperations(wms, wi[0]));
result.add(service);
}
return result;
}
/**
* Get the definitions of Rest Services from mock services.
*/
private List getRestServiceDefinitions(List mockServices){
List result = new ArrayList<>();
for (RestMockService rms : mockServices) {
// First assume it's a Rest one for now.
Service service = new Service();
service.setName(rms.getName());
service.setType(ServiceType.REST);
// Extract version from custom properties.
String version = rms.getPropertyValue(SERVICE_VERSION_PROPERTY);
if (version == null){
// TODO Throw a typed exception here...
}
service.setVersion(version);
// Then build its operations.
service.setOperations(extractOperations(rms));
result.add(service);
}
return result;
}
/**
* Extract the list of operations from MockService according WsdlInterface.
*/
private List extractOperations(MockService mockService, WsdlInterface wi){
List result = new ArrayList();
List operations = mockService.getMockOperationList();
for (MockOperation mockOperation : operations){
// Build a new operation.
Operation operation = new Operation();
operation.setName(mockOperation.getName());
// Retrieve part name from Wsdl operation coming from interface.
WsdlOperation wo = wi.getOperationByName(mockOperation.getName());
operation.setInputName(wo.getInputName());
operation.setOutputName(wo.getOutputName());
WsdlMockOperation wmo = (WsdlMockOperation)mockOperation;
operation.setDispatcher(wmo.getDispatchStyle());
// Check dispatcher configuration.
MockOperationDispatcher dispatcher = wmo.getDispatcher();
if (dispatcher instanceof QueryMatchMockOperationDispatcher){
QueryMatchMockOperationDispatcher qmDispatcher = (QueryMatchMockOperationDispatcher) dispatcher;
String query = qmDispatcher.getQueryAt(0).getQuery();
operation.setDispatcherRules(query);
}
else if (dispatcher instanceof ScriptMockOperationDispatcher){
ScriptMockOperationDispatcher sDispatcher = (ScriptMockOperationDispatcher) dispatcher;
String script = sDispatcher.getMockOperation().getScript();
operation.setDispatcherRules(script);
}
result.add(operation);
}
return result;
}
/**
* Extract the list of operations from RestMockService.
*/
private List extractOperations(RestMockService mockService){
// 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 actions = mockService.getConfig().getRestMockActionList();
for (RESTMockActionConfig action : actions){
// Check already found operation.
Operation operation = collectedOperations.get(action.getName());
if (operation == null){
// Build a new operation.
operation = new Operation();
operation.setName(action.getName());
// Complete with REST specific fields.
operation.setMethod(action.getMethod());
// Deal with dispatcher stuffs.
operation.setDispatcher(action.getDispatchStyle().toString());
if (DispatchStyles.SEQUENCE.equals(action.getDispatchStyle().toString())){
operation.setDispatcherRules(DispatchCriteriaHelper.extractPartsFromURIPattern(operation.getName()));
}
else if (DispatchStyles.SCRIPT.equals(action.getDispatchStyle().toString())){
String script = action.getDispatchPath();
operation.setDispatcherRules(script);
}
}
// Add this configuration resource path.
operation.addResourcePath(action.getResourcePath());
collectedOperations.put(action.getName(), operation);
}
return new ArrayList<>(collectedOperations.values());
}
/**
* Get message definition for an operation of a Soap mock service.
*/
private List getSoapMessageDefinitions(MockService mockService, Operation operation) throws XPathExpressionException{
Map result = new HashMap();
// Get MockOperation corresponding to operation.
MockOperation mockOperation = mockService.getMockOperationByName(operation.getName());
// Collect available test requests for this operation.
Map availableRequests = collectWsdlTestRequests(operation);
// Then filter only those that are candidates to mock response matching.
List requests = new ArrayList();
for (MockResponse mockResponse : mockOperation.getMockResponses()){
// Check if there's a corresponding request in test cases.
WsdlTestRequest matchingRequest = availableRequests.get(mockResponse.getName());
if (matchingRequest == null){
matchingRequest = availableRequests.get(mockResponse.getName() + " Request");
}
if (matchingRequest == null && mockResponse.getName().contains("Response")){
matchingRequest = availableRequests.get(mockResponse.getName().replace("Response", "Request"));
}
if (matchingRequest == null){
log.warn("No request found for response " + mockResponse.getName() + " into SoapUI project " + project.getName());
continue;
}
requests.add(matchingRequest);
}
if (DispatchStyles.QUERY_MATCH.equals(operation.getDispatcher())){
// Browse candidates and apply query dispatcher criterion to find corresponding response.
XPathExpression xpath = initializeXPathMatcher(operation);
Map matchToResponseMap = buildQueryMatchDispatchCriteriaToResponseMap((WsdlMockOperation)mockOperation);
for (WsdlTestRequest wtr : requests){
// Evaluate matcher against request and get name of corresponding response.
String dispatchCriteria = xpath.evaluate(new InputSource(new StringReader(wtr.getRequestContent())));
String correspondingResponse = matchToResponseMap.get(dispatchCriteria);
MockResponse mockResponse = mockOperation.getMockResponseByName(correspondingResponse);
if (mockResponse != null){
// Build response from MockResponse and response from matching one
Response response = buildResponse(mockResponse, dispatchCriteria);
Request request = buildRequest(wtr);
result.put(request, response);
}
}
}
else if (DispatchStyles.SCRIPT.equals(operation.getDispatcher())){
for (WsdlTestRequest wtr : requests){
MockResponse mockResponse = mockOperation.getMockResponseByName(wtr.getName().replace(" Request", ""));
if (mockResponse == null && wtr.getName().contains("Request")){
mockResponse = mockOperation.getMockResponseByName(wtr.getName().replace(" Request", " Response"));
}
if (mockResponse == null){
log.warn("No response found for request " + wtr.getName() + " into SoapUI project " + project.getName());
continue;
}
// Build response from MockResponse and response from matching one.
Response response = buildResponse(mockResponse, mockResponse.getName());
Request request = buildRequest(wtr);
result.put(request, response);
}
}
// Adapt map to list of Exchanges.
return result.entrySet().stream()
.map(entry -> new RequestResponsePair(entry.getKey(), entry.getValue()))
.collect(Collectors.toList());
}
/**
* Get message definition for an operation of a Rest mock service.
*/
private List getRestMessageDefinitions(RestMockService mockService, Operation operation){
Map result = new HashMap();
// Collect mock responses for MockOperation corresponding to operation (it may be many).
List mockResponses = new ArrayList();
for (MockOperation mockOperation : mockService.getMockOperationList()){
if (mockOperation.getName().equals(operation.getName())){
mockResponses.addAll(mockOperation.getMockResponses());
}
}
// Collect also mock action configs, organizing them within a map with response name as key.
Map mockRestActionConfigsForResponses = new HashMap();
for (RESTMockActionConfig mockActionConfig : mockService.getConfig().getRestMockActionList()){
if (mockActionConfig.getName().equals(operation.getName())){
for (RESTMockResponseConfig mockRestResponse : mockActionConfig.getResponseList()){
mockRestActionConfigsForResponses.put(mockRestResponse.getName(), mockActionConfig);
}
}
}
// Collect available test requests for this operation.
Map availableRequests = collectRestTestRequests(operation);
// Then find only those that are candidates to mock response matching.
Map requestToResponse = new HashMap();
for (MockResponse mockResponse : mockResponses){
// Check if there's a corresponding request in test cases.
RestTestRequest matchingRequest = availableRequests.get(mockResponse.getName());
if (matchingRequest == null){
matchingRequest = availableRequests.get(mockResponse.getName() + " Request");
}
if (matchingRequest == null && mockResponse.getName().contains("Response")){
matchingRequest = availableRequests.get(mockResponse.getName().replace("Response", "Request"));
}
if (matchingRequest == null){
log.warn("No request found for response " + mockResponse.getName() + " into SoapUI project " + project.getName());
continue;
}
requestToResponse.put(matchingRequest, mockResponse);
}
for (Map.Entry entry : requestToResponse.entrySet()){
RestTestRequest rtr = entry.getKey();
MockResponse mr = entry.getValue();
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
RESTMockActionConfig actionConfig = mockRestActionConfigsForResponses.get(mr.getName());
dispatchCriteria = DispatchCriteriaHelper.extractFromURIPattern(operation.getName(), actionConfig.getResourcePath());
}
else if (DispatchStyles.SCRIPT.equals(operation.getDispatcher())){
// Build a dispatch criteria that is equal to response name (that script evaluation should return...)
dispatchCriteria = mr.getName();
}
Response response = buildResponse((RestMockResponse)mr, dispatchCriteria);
Request request = buildRequest(rtr);
result.put(request, response);
}
// Adapt map to list of Exchanges.
return result.entrySet().stream()
.map(entry -> new RequestResponsePair(entry.getKey(), entry.getValue()))
.collect(Collectors.toList());
}
/**
* Collect and filter by operation all the WsldTestrequest from the current project.
*/
private Map collectWsdlTestRequests(Operation operation){
Map result = new HashMap<>();
for (TestSuite testsuite : project.getTestSuiteList()){
for (TestCase testcase : testsuite.getTestCaseList()){
for (TestStep teststep : testcase.getTestStepList()){
if (teststep instanceof WsdlTestRequestStep){
WsdlTestRequestStep ws = (WsdlTestRequestStep)teststep;
WsdlTestRequest wr = ws.getHttpRequest();
if (wr.getOperationName().equals(operation.getName())){
result.put(wr.getName(), wr);
}
}
}
}
}
return result;
}
/**
* Collect and filter by operation all the WsldTestrequest from the current project.
*/
private Map collectRestTestRequests(Operation operation){
Map result = new HashMap();
for (TestSuite testsuite : project.getTestSuiteList()){
for (TestCase testcase : testsuite.getTestCaseList()){
for (TestStep teststep : testcase.getTestStepList()){
if (teststep instanceof RestTestRequestStep){
RestTestRequestStep rs = (RestTestRequestStep)teststep;
RestTestRequest rr = rs.getTestRequest();
if (rs.getResourcePath().equals(operation.getName())){
result.put(rr.getName(), rr);
}
}
}
}
}
return result;
}
/**
* Build a XPathMatcher based on operation dispatcher rules.
*/
private XPathExpression initializeXPathMatcher(Operation operation) throws XPathExpressionException {
return SoapUIXPathBuilder.buildXPathMatcherFromRules(operation.getDispatcherRules());
}
/**
* Build a map where keys are dispatch criteria and values response name.
*/
private Map buildQueryMatchDispatchCriteriaToResponseMap(WsdlMockOperation wmo){
Map matchResponseMap = new HashMap();
//MockOperationDispatcher dispatcher = wmo.getMockOperationDispatcher();
MockOperationDispatcher dispatcher = wmo.getDispatcher();
if (dispatcher instanceof QueryMatchMockOperationDispatcher){
QueryMatchMockOperationDispatcher qmDispatcher = (QueryMatchMockOperationDispatcher) dispatcher;
for (int i=0; i buildHeaders(StringToStringsMap requestHeaders){
if (requestHeaders == null || requestHeaders.size() == 0){
return null;
}
// Prepare and map the set of headers.
Set headers = new HashSet<>();
for (Map.Entry> entry : requestHeaders.entrySet()){
Header header = new Header();
header.setName(entry.getKey());
header.setValues(new HashSet<>(entry.getValue()));
headers.add(header);
}
return headers;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy