/* * SoapUI, Copyright (C) 2004-2016 SmartBear Software * * Licensed under the EUPL, Version 1.1 or - as soon as they will be approved by the European Commission - subsequent * versions of the EUPL (the "Licence"); * You may not use this work except in compliance with the Licence. * You may obtain a copy of the Licence at: * * http://ec.europa.eu/idabc/eupl * * Unless required by applicable law or agreed to in writing, software distributed under the Licence is * distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either * express or implied. See the Licence for the specific language governing permissions and limitations * under the Licence. */ package com.eviware.soapui.impl.wsdl.teststeps; import com.eviware.soapui.SoapUI; import com.eviware.soapui.config.RequestStepConfig; import com.eviware.soapui.config.TestStepConfig; import com.eviware.soapui.impl.support.http.HttpRequestTestStep; import com.eviware.soapui.impl.wsdl.AbstractWsdlModelItem; 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.WsdlRequest; import com.eviware.soapui.impl.wsdl.WsdlSubmit; import com.eviware.soapui.impl.wsdl.submit.transports.http.BaseHttpRequestTransport; import com.eviware.soapui.impl.wsdl.submit.transports.http.WsdlResponse; import com.eviware.soapui.impl.wsdl.submit.transports.http.support.attachments.WsdlSinglePartHttpResponse; import com.eviware.soapui.impl.wsdl.support.assertions.AssertedXPathsContainer; import com.eviware.soapui.impl.wsdl.support.wsdl.WsdlUtils; import com.eviware.soapui.impl.wsdl.testcase.WsdlTestCase; import com.eviware.soapui.impl.wsdl.testcase.WsdlTestRunContext; import com.eviware.soapui.impl.wsdl.teststeps.assertions.TestAssertionRegistry.AssertableType; import com.eviware.soapui.model.ModelItem; import com.eviware.soapui.model.iface.Interface; import com.eviware.soapui.model.iface.Operation; import com.eviware.soapui.model.iface.Request.SubmitException; import com.eviware.soapui.model.iface.Submit; import com.eviware.soapui.model.project.Project; import com.eviware.soapui.model.propertyexpansion.PropertyExpander; import com.eviware.soapui.model.propertyexpansion.PropertyExpansion; import com.eviware.soapui.model.propertyexpansion.PropertyExpansionContainer; import com.eviware.soapui.model.propertyexpansion.PropertyExpansionsResult; import com.eviware.soapui.model.support.DefaultTestStepProperty; import com.eviware.soapui.model.support.InterfaceListenerAdapter; import com.eviware.soapui.model.support.ModelSupport; import com.eviware.soapui.model.support.ProjectListenerAdapter; import com.eviware.soapui.model.support.TestStepBeanProperty; import com.eviware.soapui.model.testsuite.Assertable; import com.eviware.soapui.model.testsuite.AssertionError; import com.eviware.soapui.model.testsuite.AssertionsListener; import com.eviware.soapui.model.testsuite.OperationTestStep; import com.eviware.soapui.model.testsuite.TestAssertion; import com.eviware.soapui.model.testsuite.TestCaseRunContext; import com.eviware.soapui.model.testsuite.TestCaseRunner; import com.eviware.soapui.model.testsuite.TestStep; import com.eviware.soapui.model.testsuite.TestStepResult; import com.eviware.soapui.model.testsuite.TestStepResult.TestStepStatus; import com.eviware.soapui.security.Securable; import com.eviware.soapui.support.resolver.ChangeOperationResolver; import com.eviware.soapui.support.resolver.ImportInterfaceResolver; import com.eviware.soapui.support.resolver.RemoveTestStepResolver; import com.eviware.soapui.support.resolver.ResolveContext; import com.eviware.soapui.support.resolver.ResolveContext.PathToResolve; import com.eviware.soapui.support.types.StringToStringsMap; import org.apache.log4j.Logger; import org.apache.xmlbeans.SchemaType; import org.apache.xmlbeans.XmlString; import javax.swing.ImageIcon; import javax.xml.namespace.QName; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.List; import java.util.Map; /** * WsdlTestStep that executes a WsdlTestRequest * * @author Ole.Matzura */ public class WsdlTestRequestStep extends WsdlTestStepWithProperties implements OperationTestStep, PropertyChangeListener, PropertyExpansionContainer, Assertable, HttpRequestTestStep, Securable { private final static Logger log = Logger.getLogger(WsdlTestRequestStep.class); private RequestStepConfig requestStepConfig; private WsdlTestRequest testRequest; private WsdlOperation wsdlOperation; private final InternalProjectListener projectListener = new InternalProjectListener(); private final InternalInterfaceListener interfaceListener = new InternalInterfaceListener(); private WsdlSubmit<WsdlRequest> submit; public WsdlTestRequestStep(WsdlTestCase testCase, TestStepConfig config, boolean forLoadTest) { super(testCase, config, true, forLoadTest); if (getConfig().getConfig() != null) { requestStepConfig = (RequestStepConfig) getConfig().getConfig().changeType(RequestStepConfig.type); wsdlOperation = findWsdlOperation(); if (wsdlOperation == null) { log.error("Could not find operation [" + requestStepConfig.getOperation() + "] in interface [" + requestStepConfig.getInterface() + "] for test request [" + getName() + "] in TestCase [" + getTestCase().getTestSuite().getName() + "/" + getTestCase().getName() + "]"); // requestStepConfig.setRequest(null); setDisabled(true); } else { initTestRequest(config, forLoadTest); } } else { requestStepConfig = (RequestStepConfig) getConfig().addNewConfig().changeType(RequestStepConfig.type); } // init properties if (testRequest != null) { initRequestProperties(); } } private void initRequestProperties() { addProperty(new TestStepBeanProperty("Endpoint", false, testRequest, "endpoint", this, false)); addProperty(new TestStepBeanProperty("Username", false, testRequest, "username", this, true)); addProperty(new TestStepBeanProperty("Password", false, testRequest, "password", this, true)); addProperty(new TestStepBeanProperty("Domain", false, testRequest, "domain", this, false)); addProperty(new TestStepBeanProperty("AuthType", false, testRequest, "authType", this, true) { @Override public String getDefaultValue() { // TODO Auto-generated method stub return "XXX"; } }); addProperty(new TestStepBeanProperty("Request", false, testRequest, "requestContent", this, true) { @Override public String getDefaultValue() { return getOperation().createRequest(true); } @Override public SchemaType getSchemaType() { try { WsdlInterface iface = getOperation().getInterface(); if (WsdlUtils.isRpc(iface.getBinding())) { return WsdlUtils.generateRpcBodyType(getOperation()); } else { return iface.getDefinitionContext().getSchemaTypeSystem() .findElement(getOperation().getRequestBodyElementQName()).getType(); } } catch (Exception e) { SoapUI.logError(e); return XmlString.type; } } @Override public QName getType() { return getSchemaType().getName(); } }); addProperty(new TestStepBeanProperty("Response", true, testRequest, "responseContent", this) { @Override public String getDefaultValue() { return getOperation().createResponse(true); } }); addProperty(new DefaultTestStepProperty("RawRequest", true, this) { @Override public String getValue() { WsdlResponse response = testRequest.getResponse(); return response == null ? null : response.getRequestContent(); } }); } private void initTestRequest(TestStepConfig config, boolean forLoadTest) { if (!forLoadTest) { wsdlOperation.getInterface().getProject().addProjectListener(projectListener); wsdlOperation.getInterface().addInterfaceListener(interfaceListener); // we need to listen for name changes which happen when // interfaces are updated.. wsdlOperation.getInterface().addPropertyChangeListener(this); wsdlOperation.addPropertyChangeListener(this); } testRequest = new WsdlTestRequest(wsdlOperation, requestStepConfig.getRequest(), this, forLoadTest); testRequest.addPropertyChangeListener(this); if (config.isSetName()) { testRequest.setName(config.getName()); } else { config.setName(testRequest.getName()); } } @Override public WsdlTestStep clone(WsdlTestCase targetTestCase, String name) { beforeSave(); TestStepConfig config = (TestStepConfig) getConfig().copy(); RequestStepConfig stepConfig = (RequestStepConfig) config.getConfig().changeType(RequestStepConfig.type); while (stepConfig.getRequest().sizeOfAttachmentArray() > 0) { stepConfig.getRequest().removeAttachment(0); } config.setName(name); stepConfig.getRequest().setName(name); WsdlTestRequestStep result = (WsdlTestRequestStep) targetTestCase.addTestStep(config); testRequest.copyAttachmentsTo(result.getTestRequest()); return result; } private WsdlOperation findWsdlOperation() { WsdlTestCase testCase = getTestCase(); if (testCase == null || testCase.getTestSuite() == null) { return null; } Project project = testCase.getTestSuite().getProject(); WsdlOperation operation = null; for (int c = 0; c < project.getInterfaceCount(); c++) { if (project.getInterfaceAt(c).getName().equals(requestStepConfig.getInterface())) { WsdlInterface iface = (WsdlInterface) project.getInterfaceAt(c); for (int i = 0; i < iface.getOperationCount(); i++) { if (iface.getOperationAt(i).getName().equals(requestStepConfig.getOperation())) { operation = iface.getOperationAt(i); break; } } if (operation != null) { break; } } } return operation; } public String getInterfaceName() { return requestStepConfig.getInterface(); } public String getOperationName() { return requestStepConfig.getOperation(); } @Override public void release() { super.release(); if (wsdlOperation == null) { wsdlOperation = findWsdlOperation(); } if (wsdlOperation != null) { wsdlOperation.removePropertyChangeListener(this); wsdlOperation.getInterface().getProject().removeProjectListener(projectListener); wsdlOperation.getInterface().removeInterfaceListener(interfaceListener); wsdlOperation.getInterface().removePropertyChangeListener(this); } // could be null if initialization failed.. if (testRequest != null) { testRequest.removePropertyChangeListener(this); testRequest.release(); } } @Override public void resetConfigOnMove(TestStepConfig config) { super.resetConfigOnMove(config); requestStepConfig = (RequestStepConfig) config.getConfig().changeType(RequestStepConfig.type); testRequest.updateConfig(requestStepConfig.getRequest()); } @Override public ImageIcon getIcon() { return testRequest == null ? null : testRequest.getIcon(); } public WsdlTestRequest getTestRequest() { return testRequest; } @Override public void setName(String name) { super.setName(name); testRequest.setName(name); } public void propertyChange(PropertyChangeEvent event) { // TODO Some of these properties should be pulled up as they are common for may steps // FIXME The property names shouldn't be hardcoded if (event.getSource() == testRequest) { if (event.getNewValue() instanceof WsdlSinglePartHttpResponse) { WsdlSinglePartHttpResponse response = (WsdlSinglePartHttpResponse) event.getNewValue(); WsdlRequest request = response.getRequest(); byte[] rawRequest = response.getRawRequestData(); firePropertyValueChanged("Response", String.valueOf(response), null); firePropertyValueChanged("Request", String.valueOf(request), null); firePropertyValueChanged("RawRequest", String.valueOf(rawRequest), null); } if (event.getPropertyName().equals("domain")) { delegatePropertyChange("Domain", event); } else if (event.getPropertyName().equals("password")) { delegatePropertyChange("Password", event); } else if (event.getPropertyName().equals("username")) { delegatePropertyChange("Username", event); } else if (event.getPropertyName().equals("endpoint")) { delegatePropertyChange("Endpoint", event); } } if (event.getSource() == wsdlOperation) { if (event.getPropertyName().equals(Operation.NAME_PROPERTY)) { requestStepConfig.setOperation((String) event.getNewValue()); } } else if (event.getSource() == wsdlOperation.getInterface()) { if (event.getPropertyName().equals(Interface.NAME_PROPERTY)) { requestStepConfig.setInterface((String) event.getNewValue()); } } else if (event.getPropertyName().equals(TestAssertion.CONFIGURATION_PROPERTY) || event.getPropertyName().equals(TestAssertion.DISABLED_PROPERTY)) { if (getTestRequest().getResponse() != null) { getTestRequest().assertResponse(new WsdlTestRunContext(this)); } } else { if (event.getSource() == testRequest && event.getPropertyName().equals(WsdlTestRequest.NAME_PROPERTY)) { if (!super.getName().equals((String) event.getNewValue())) { super.setName((String) event.getNewValue()); } } notifyPropertyChanged(event.getPropertyName(), event.getOldValue(), event.getNewValue()); } } private void delegatePropertyChange(String customPropertyname, PropertyChangeEvent event) { firePropertyValueChanged(customPropertyname, String.valueOf(event.getOldValue()), String.valueOf(event.getNewValue())); } public TestStepResult run(TestCaseRunner runner, TestCaseRunContext runContext) { WsdlTestRequestStepResult testStepResult = new WsdlTestRequestStepResult(this); testStepResult.startTimer(); runContext.setProperty(AssertedXPathsContainer.ASSERTEDXPATHSCONTAINER_PROPERTY, testStepResult); try { submit = testRequest.submit(runContext, false); WsdlResponse response = (WsdlResponse) submit.getResponse(); if (submit.getStatus() != Submit.Status.CANCELED) { if (submit.getStatus() == Submit.Status.ERROR) { testStepResult.setStatus(TestStepStatus.FAILED); testStepResult.addMessage(submit.getError().toString()); testRequest.setResponse(null, runContext); } else if (response == null) { testStepResult.setStatus(TestStepStatus.FAILED); testStepResult.addMessage("Request is missing response"); testRequest.setResponse(null, runContext); } else { runContext.setProperty(AssertedXPathsContainer.ASSERTEDXPATHSCONTAINER_PROPERTY, testStepResult); testRequest.setResponse(response, runContext); testStepResult.setTimeTaken(response.getTimeTaken()); testStepResult.setSize(response.getContentLength()); switch (testRequest.getAssertionStatus()) { case FAILED: testStepResult.setStatus(TestStepStatus.FAILED); break; case VALID: testStepResult.setStatus(TestStepStatus.OK); break; case UNKNOWN: testStepResult.setStatus(TestStepStatus.UNKNOWN); break; } testStepResult.setResponse(response, testStepResult.getStatus() != TestStepStatus.FAILED); } } else { testStepResult.setStatus(TestStepStatus.CANCELED); testStepResult.addMessage("Request was canceled"); } if (response != null) { testStepResult.setRequestContent(response.getRequestContent(), testStepResult.getStatus() != TestStepStatus.FAILED); } else { testStepResult.setRequestContent(testRequest.getRequestContent(), testStepResult.getStatus() != TestStepStatus.FAILED); } testStepResult.stopTimer(); } catch (SubmitException e) { testStepResult.setStatus(TestStepStatus.FAILED); testStepResult.addMessage("SubmitException: " + e); testStepResult.stopTimer(); } finally { submit = null; } testStepResult.setDomain(PropertyExpander.expandProperties(runContext, testRequest.getDomain())); testStepResult.setUsername(PropertyExpander.expandProperties(runContext, testRequest.getUsername())); testStepResult.setPassword(PropertyExpander.expandProperties(runContext, testRequest.getPassword())); testStepResult.setEndpoint(PropertyExpander.expandProperties(runContext, testRequest.getEndpoint())); testStepResult.setEncoding(PropertyExpander.expandProperties(runContext, testRequest.getEncoding())); if (testStepResult.getStatus() != TestStepStatus.CANCELED) { AssertionStatus assertionStatus = testRequest.getAssertionStatus(); switch (assertionStatus) { case FAILED: { testStepResult.setStatus(TestStepStatus.FAILED); if (getAssertionCount() == 0) { testStepResult.addMessage("Invalid/empty response"); } else { for (int c = 0; c < getAssertionCount(); c++) { WsdlMessageAssertion assertion = getAssertionAt(c); AssertionError[] errors = assertion.getErrors(); if (errors != null) { for (AssertionError error : errors) { testStepResult.addMessage("[" + assertion.getName() + "] " + error.getMessage()); } } } } break; } // default : testStepResult.setStatus( TestStepStatus.OK ); break; } } if (testRequest.isDiscardResponse() && !SoapUI.getDesktop().hasDesktopPanel(this)) { testRequest.setResponse(null, runContext); runContext.removeProperty(BaseHttpRequestTransport.RESPONSE); } return testStepResult; } public WsdlMessageAssertion getAssertionAt(int index) { return testRequest.getAssertionAt(index); } public int getAssertionCount() { return testRequest == null ? 0 : testRequest.getAssertionCount(); } public WsdlTestRequest getHttpRequest() { return testRequest; } public class InternalProjectListener extends ProjectListenerAdapter { @Override public void interfaceRemoved(Interface iface) { if (wsdlOperation != null && wsdlOperation.getInterface().equals(iface)) { log.debug("Removing test step due to removed interface"); (getTestCase()).removeTestStep(WsdlTestRequestStep.this); } } } public class InternalInterfaceListener extends InterfaceListenerAdapter { @Override public void operationRemoved(Operation operation) { if (operation == wsdlOperation) { log.debug("Removing test step due to removed operation"); (getTestCase()).removeTestStep(WsdlTestRequestStep.this); } } @Override public void operationUpdated(Operation operation) { if (operation == wsdlOperation) { requestStepConfig.setOperation(operation.getName()); } } } @Override public boolean cancel() { if (submit == null) { return false; } submit.cancel(); return true; } @Override public Collection<Interface> getRequiredInterfaces() { ArrayList<Interface> result = new ArrayList<Interface>(); result.add(findWsdlOperation().getInterface()); return result; } public String getDefaultSourcePropertyName() { return "Response"; } public String getDefaultTargetPropertyName() { return "Request"; } @Override public boolean dependsOn(AbstractWsdlModelItem<?> modelItem) { if (modelItem instanceof Interface && testRequest.getOperation().getInterface() == modelItem) { return true; } else if (modelItem instanceof Operation && testRequest.getOperation() == modelItem) { return true; } return false; } @Override public void beforeSave() { super.beforeSave(); if (testRequest != null) { testRequest.beforeSave(); } } @Override public String getDescription() { return testRequest == null ? "<missing>" : testRequest.getDescription(); } @Override public void setDescription(String description) { if (testRequest != null) { testRequest.setDescription(description); } } public void setOperation(WsdlOperation operation) { if (wsdlOperation == operation) { return; } WsdlOperation oldOperation = wsdlOperation; wsdlOperation = operation; requestStepConfig.setInterface(operation.getInterface().getName()); requestStepConfig.setOperation(operation.getName()); if (oldOperation != null) { oldOperation.removePropertyChangeListener(this); } wsdlOperation.addPropertyChangeListener(this); initTestRequest(this.getConfig(), false); testRequest.setOperation(wsdlOperation); } @SuppressWarnings("unchecked") @Override public List<? extends ModelItem> getChildren() { return testRequest == null ? Collections.EMPTY_LIST : testRequest.getAssertionList(); } public PropertyExpansion[] getPropertyExpansions() { if (testRequest == null) { return new PropertyExpansion[0]; } PropertyExpansionsResult result = new PropertyExpansionsResult(this, testRequest); result.extractAndAddAll("requestContent"); result.extractAndAddAll("endpoint"); result.extractAndAddAll("username"); result.extractAndAddAll("password"); result.extractAndAddAll("domain"); StringToStringsMap requestHeaders = testRequest.getRequestHeaders(); for (Map.Entry<String, List<String>> headerEntry : requestHeaders.entrySet()) { for (String value : headerEntry.getValue()) { result.extractAndAddAll(new HttpTestRequestStep.RequestHeaderHolder(headerEntry.getKey(), value, testRequest), "value"); } } testRequest.addWsaPropertyExpansions(result, testRequest.getWsaConfig(), this); testRequest.addJMSHeaderExpansions(result, testRequest.getJMSHeaderConfig(), this); return result.toArray(new PropertyExpansion[result.size()]); } public TestAssertion addAssertion(String type) { WsdlMessageAssertion result = testRequest.addAssertion(type); return result; } public void addAssertionsListener(AssertionsListener listener) { testRequest.addAssertionsListener(listener); } public TestAssertion cloneAssertion(TestAssertion source, String name) { return testRequest.cloneAssertion(source, name); } public String getAssertableContentAsXml() { return testRequest.getAssertableContentAsXml(); } public String getAssertableContent() { return testRequest.getAssertableContent(); } public AssertableType getAssertableType() { return testRequest.getAssertableType(); } public TestAssertion getAssertionByName(String name) { return testRequest.getAssertionByName(name); } public List<TestAssertion> getAssertionList() { return testRequest.getAssertionList(); } public AssertionStatus getAssertionStatus() { return testRequest.getAssertionStatus(); } public Interface getInterface() { return wsdlOperation == null ? null : wsdlOperation.getInterface(); } public WsdlOperation getOperation() { return wsdlOperation; } public TestStep getTestStep() { return this; } public void removeAssertion(TestAssertion assertion) { testRequest.removeAssertion(assertion); } public TestAssertion moveAssertion(int ix, int whereTo) { return testRequest.moveAssertion(ix, whereTo); } public void removeAssertionsListener(AssertionsListener listener) { testRequest.removeAssertionsListener(listener); } public Map<String, TestAssertion> getAssertions() { return testRequest.getAssertions(); } @Override public void prepare(TestCaseRunner testRunner, TestCaseRunContext testRunContext) throws Exception { super.prepare(testRunner, testRunContext); testRequest.setResponse(null, testRunContext); for (TestAssertion assertion : testRequest.getAssertionList()) { assertion.prepare(testRunner, testRunContext); } } public String getDefaultAssertableContent() { return testRequest.getDefaultAssertableContent(); } @SuppressWarnings("unchecked") public void resolve(ResolveContext<?> context) { super.resolve(context); if (wsdlOperation == null) { // not solved and we have it in list do not add it. if (context.hasThisModelItem(this, "Missing SOAP Operation in Project", requestStepConfig.getInterface() + "/" + requestStepConfig.getOperation())) { return; } context.addPathToResolve(this, "Missing SOAP Operation in Project", requestStepConfig.getInterface() + "/" + requestStepConfig.getOperation()).addResolvers( new RemoveTestStepResolver(this), new ImportInterfaceResolver(this) { @Override protected boolean update() { wsdlOperation = findWsdlOperation(); if (wsdlOperation == null) { return false; } initTestRequest(getConfig(), false); initRequestProperties(); setDisabled(false); return true; } }, new ChangeOperationResolver(this, "Operation") { @Override public boolean update() { WsdlOperation wsdlOperation = (WsdlOperation) getSelectedOperation(); if (wsdlOperation == null) { return false; } setOperation(wsdlOperation); initTestRequest(getConfig(), false); initRequestProperties(); setDisabled(false); return true; } protected Interface[] getInterfaces(WsdlProject project) { List<WsdlInterface> interfaces = ModelSupport.getChildren(project, WsdlInterface.class); return interfaces.toArray(new Interface[interfaces.size()]); } } ); } else { testRequest.resolve(context); if (context.hasThisModelItem(this, "Missing SOAP Operation in Project", requestStepConfig.getInterface() + "/" + requestStepConfig.getOperation())) { PathToResolve path = context.getPath(this, "Missing SOAP Operation in Project", requestStepConfig.getInterface() + "/" + requestStepConfig.getOperation()); path.setSolved(true); } } } }