/*
* 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.HttpRequestConfig;
import com.eviware.soapui.config.RequestStepConfig;
import com.eviware.soapui.config.TestStepConfig;
import com.eviware.soapui.impl.rest.support.RestParamProperty;
import com.eviware.soapui.impl.rest.support.RestRequestConverter;
import com.eviware.soapui.impl.support.AbstractHttpRequest;
import com.eviware.soapui.impl.support.http.HttpRequest;
import com.eviware.soapui.impl.wsdl.AbstractWsdlModelItem;
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.HttpResponse;
import com.eviware.soapui.impl.wsdl.submit.transports.http.SinglePartHttpResponse;
import com.eviware.soapui.impl.wsdl.support.ExternalDependency;
import com.eviware.soapui.impl.wsdl.support.assertions.AssertedXPathsContainer;
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.Request.SubmitException;
import com.eviware.soapui.model.iface.Submit;
import com.eviware.soapui.model.propertyexpansion.PropertyExpander;
import com.eviware.soapui.model.propertyexpansion.PropertyExpansion;
import com.eviware.soapui.model.propertyexpansion.PropertyExpansionsResult;
import com.eviware.soapui.model.support.DefaultTestStepProperty;
import com.eviware.soapui.model.support.TestPropertyListenerAdapter;
import com.eviware.soapui.model.support.TestStepBeanProperty;
import com.eviware.soapui.model.testsuite.AssertionError;
import com.eviware.soapui.model.testsuite.AssertionsListener;
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.TestProperty;
import com.eviware.soapui.model.testsuite.TestStep;
import com.eviware.soapui.model.testsuite.TestStepProperty;
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.ResolveContext;
import com.eviware.soapui.support.types.StringToStringsMap;
import org.apache.log4j.Logger;
import org.apache.xmlbeans.SchemaType;
import javax.swing.ImageIcon;
import javax.xml.namespace.QName;
import java.beans.PropertyChangeEvent;
import java.util.Collections;
import java.util.List;
import java.util.Map;
public class HttpTestRequestStep extends WsdlTestStepWithProperties implements HttpTestRequestStepInterface, Securable {
@SuppressWarnings("unused")
private final static Logger log = Logger.getLogger(HttpTestRequestStep.class);
private HttpRequestConfig httpRequestConfig;
private HttpTestRequest testRequest;
private WsdlSubmit<HttpRequest> submit;
public HttpTestRequestStep(WsdlTestCase testCase, TestStepConfig config, boolean forLoadTest) {
super(testCase, config, true, forLoadTest);
if (getConfig().getConfig() != null) {
httpRequestConfig = RestRequestConverter.updateIfNeeded(getConfig().getConfig());
getConfig().setConfig(httpRequestConfig);
httpRequestConfig = (HttpRequestConfig) getConfig().getConfig();
testRequest = buildTestRequest(forLoadTest);
testRequest.addPropertyChangeListener(this);
testRequest.addTestPropertyListener(new InternalTestPropertyListener());
if (config.isSetName()) {
testRequest.setName(config.getName());
} else {
config.setName(testRequest.getName());
}
} else {
httpRequestConfig = (HttpRequestConfig) getConfig().addNewConfig().changeType(HttpRequestConfig.type);
}
for (TestProperty property : testRequest.getProperties().values()) {
addProperty(new RestTestStepProperty((RestParamProperty) property));
}
// init default properties
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));
// init properties
addProperty(new TestStepBeanProperty("Request", false, testRequest, "requestContent", this, true) {
@Override
public String getDefaultValue() {
return createDefaultRequestContent();
}
});
addProperty(new TestStepBeanProperty(WsdlTestStepWithProperties.RESPONSE_AS_XML, true, testRequest,
"responseContentAsXml", this) {
@Override
public String getDefaultValue() {
return createDefaultResponseXmlContent();
}
});
addProperty(new TestStepBeanProperty("Response", true, testRequest, "responseContentAsString", this) {
@Override
public String getDefaultValue() {
return createDefaultRawResponseContent();
}
});
addProperty(new DefaultTestStepProperty("RawRequest", true, this) {
@Override
public String getValue() {
HttpResponse response = testRequest.getResponse();
return response == null ? null : response.getRequestContent();
}
});
}
protected HttpTestRequest buildTestRequest(boolean forLoadTest) {
return new HttpTestRequest(httpRequestConfig, this, forLoadTest);
}
protected String createDefaultRawResponseContent() {
return "";
}
protected String createDefaultResponseXmlContent() {
return "";
}
protected String createDefaultRequestContent() {
return "";
}
public HttpRequestConfig getRequestStepConfig() {
return httpRequestConfig;
}
@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;
}
@Override
public void release() {
super.release();
// could be null if initialization failed..
if (testRequest != null) {
testRequest.removePropertyChangeListener(this);
testRequest.release();
}
}
@Override
public void resetConfigOnMove(TestStepConfig config) {
super.resetConfigOnMove(config);
httpRequestConfig = (HttpRequestConfig) config.getConfig().changeType(HttpRequestConfig.type);
testRequest.updateConfig(httpRequestConfig);
}
@Override
public ImageIcon getIcon() {
return testRequest == null ? null : testRequest.getIcon();
}
public HttpTestRequest 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 SinglePartHttpResponse) {
SinglePartHttpResponse response = (SinglePartHttpResponse) event.getNewValue();
firePropertyValueChanged("Response", String.valueOf(response), null);
String XMLCOntent = response.getContentAsXml();
firePropertyValueChanged("ResponseAsXml", String.valueOf(XMLCOntent), 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.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) {
RestRequestStepResult testStepResult = new RestRequestStepResult(this);
try {
submit = testRequest.submit(runContext, false);
HttpResponse response = (HttpResponse) 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());
testStepResult.setResponse(response);
switch (testRequest.getAssertionStatus()) {
case FAILED:
testStepResult.setStatus(TestStepStatus.FAILED);
break;
case VALID:
testStepResult.setStatus(TestStepStatus.OK);
break;
case UNKNOWN:
testStepResult.setStatus(TestStepStatus.UNKNOWN);
break;
}
}
} else {
testStepResult.setStatus(TestStepStatus.CANCELED);
testStepResult.addMessage("Request was canceled");
}
if (response != null) {
testStepResult.setRequestContent(response.getRequestContent());
testStepResult.addProperty("URL", response.getURL() == null ? "<missing>" : response.getURL().toString());
testStepResult.addProperty("Method", String.valueOf(response.getMethod()));
testStepResult.addProperty("StatusCode", String.valueOf(response.getStatusCode()));
testStepResult.addProperty("HTTP Version", response.getHttpVersion());
} else {
testStepResult.addMessage("Missing Response");
testStepResult.setRequestContent(testRequest.getRequestContent());
}
} catch (SubmitException e) {
testStepResult.setStatus(TestStepStatus.FAILED);
testStepResult.addMessage("SubmitException: " + e);
} finally {
submit = null;
}
testStepResult.setDomain(PropertyExpander.expandProperties(runContext, testRequest.getDomain()));
testStepResult.setUsername(PropertyExpander.expandProperties(runContext, testRequest.getUsername()));
testStepResult.setEndpoint(PropertyExpander.expandProperties(runContext, testRequest.getEndpoint()));
testStepResult.setPassword(PropertyExpander.expandProperties(runContext, testRequest.getPassword()));
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;
}
}
}
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();
}
@Override
public boolean cancel() {
if (submit == null) {
return false;
}
submit.cancel();
return true;
}
@Override
public boolean dependsOn(AbstractWsdlModelItem<?> modelItem) {
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);
}
}
@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 RequestHeaderHolder(headerEntry.getKey(), value, testRequest), "value");
}
}
for (String key : testRequest.getParams().getPropertyNames()) {
result.extractAndAddAll(new RequestParamHolder(key), "value");
}
return result.toArray(new PropertyExpansion[result.size()]);
}
public AbstractHttpRequest<?> getHttpRequest() {
return testRequest;
}
public static class RequestHeaderHolder {
private final String key;
private final String oldValue;
private AbstractHttpRequest<?> testRequest;
public RequestHeaderHolder(String key, String oldValue, AbstractHttpRequest<?> testRequest) {
this.key = key;
this.oldValue = oldValue;
this.testRequest = testRequest;
}
public String getValue() {
return oldValue;
}
public void setValue(String value) {
StringToStringsMap valueMap = testRequest.getRequestHeaders();
valueMap.replace(key, oldValue, value);
testRequest.setRequestHeaders(valueMap);
}
}
public class RequestParamHolder {
private final String name;
public RequestParamHolder(String name) {
this.name = name;
}
public String getValue() {
return testRequest.getParams().getPropertyValue(name);
}
public void setValue(String value) {
testRequest.setPropertyValue(name, value);
}
}
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 null;
}
public TestStep getTestStep() {
return this;
}
public void removeAssertion(TestAssertion assertion) {
testRequest.removeAssertion(assertion);
}
public void removeAssertionsListener(AssertionsListener listener) {
testRequest.removeAssertionsListener(listener);
}
public TestAssertion moveAssertion(int ix, int offset) {
return testRequest.moveAssertion(ix, offset);
}
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 getDefaultSourcePropertyName() {
return WsdlTestStepWithProperties.RESPONSE_AS_XML;
}
public String getDefaultTargetPropertyName() {
return "Request";
}
public String getDefaultAssertableContent() {
return testRequest.getDefaultAssertableContent();
}
public void resolve(ResolveContext<?> context) {
super.resolve(context);
testRequest.resolve(context);
}
@Override
protected void addExternalDependencies(List<ExternalDependency> dependencies) {
super.addExternalDependencies(dependencies);
testRequest.addExternalDependencies(dependencies);
}
private class InternalTestPropertyListener extends TestPropertyListenerAdapter {
@Override
public void propertyAdded(String name) {
HttpTestRequestStep.this.addProperty(new RestTestStepProperty(getTestRequest().getProperty(name)), true);
}
@Override
public void propertyRemoved(String name) {
HttpTestRequestStep.this.deleteProperty(name, true);
}
@Override
public void propertyRenamed(String oldName, String newName) {
HttpTestRequestStep.this.propertyRenamed(oldName);
}
@Override
public void propertyValueChanged(String name, String oldValue, String newValue) {
HttpTestRequestStep.this.firePropertyValueChanged(name, oldValue, newValue);
}
@Override
public void propertyMoved(String name, int oldIndex, int newIndex) {
HttpTestRequestStep.this.firePropertyMoved(name, oldIndex, newIndex);
}
}
private class RestTestStepProperty implements TestStepProperty {
private RestParamProperty property;
public RestTestStepProperty(RestParamProperty property) {
this.property = property;
}
public TestStep getTestStep() {
return HttpTestRequestStep.this;
}
public String getName() {
return property.getName();
}
public String getDescription() {
return property.getDescription();
}
public String getValue() {
return property.getValue();
}
public String getDefaultValue() {
return property.getDefaultValue();
}
public void setValue(String value) {
property.setValue(value);
}
public boolean isReadOnly() {
return false;
}
public QName getType() {
return property.getType();
}
public ModelItem getModelItem() {
return getTestRequest();
}
@Override
public boolean isRequestPart() {
return true;
}
@Override
public SchemaType getSchemaType() {
return property.getSchemaType();
}
}
}