/* * 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.assertions.basic; import com.eviware.soapui.SoapUI; import com.eviware.soapui.config.TestAssertionConfig; import com.eviware.soapui.impl.rest.RestResource; import com.eviware.soapui.impl.rest.RestService; import com.eviware.soapui.impl.support.AbstractInterface; import com.eviware.soapui.impl.support.DefinitionContext; import com.eviware.soapui.impl.wadl.WadlDefinitionContext; import com.eviware.soapui.impl.wadl.support.WadlValidator; import com.eviware.soapui.impl.wsdl.WsdlInterface; import com.eviware.soapui.impl.wsdl.WsdlOperation; import com.eviware.soapui.impl.wsdl.panels.assertions.AssertionCategoryMapping; import com.eviware.soapui.impl.wsdl.panels.assertions.AssertionListEntry; import com.eviware.soapui.impl.wsdl.submit.RestMessageExchange; import com.eviware.soapui.impl.wsdl.submit.WsdlMessageExchange; import com.eviware.soapui.impl.wsdl.support.PathUtils; import com.eviware.soapui.impl.wsdl.support.soap.SoapVersion; import com.eviware.soapui.impl.wsdl.support.wsdl.WsdlContext; import com.eviware.soapui.impl.wsdl.support.wsdl.WsdlValidator; import com.eviware.soapui.impl.wsdl.teststeps.WsdlMessageAssertion; import com.eviware.soapui.impl.wsdl.teststeps.assertions.AbstractTestAssertionFactory; import com.eviware.soapui.model.TestPropertyHolder; import com.eviware.soapui.model.iface.MessageExchange; import com.eviware.soapui.model.iface.SubmitContext; import com.eviware.soapui.model.propertyexpansion.PropertyExpansionContext; import com.eviware.soapui.model.testsuite.Assertable; import com.eviware.soapui.model.testsuite.AssertionError; import com.eviware.soapui.model.testsuite.AssertionException; import com.eviware.soapui.model.testsuite.RequestAssertion; import com.eviware.soapui.model.testsuite.ResponseAssertion; import com.eviware.soapui.model.testsuite.TestCaseRunContext; import com.eviware.soapui.model.testsuite.TestCaseRunner; import com.eviware.soapui.support.StringUtils; import com.eviware.soapui.support.UISupport; import com.eviware.soapui.support.xml.XmlObjectConfigurationBuilder; import com.eviware.soapui.support.xml.XmlObjectConfigurationReader; import org.apache.xmlbeans.XmlObject; import java.util.HashMap; import java.util.Map; /** * Asserts that a request or response message complies with its related WSDL * definition / XML Schema * * @author Ole.Matzura */ public class SchemaComplianceAssertion extends WsdlMessageAssertion implements RequestAssertion, ResponseAssertion { public static final String ID = "Schema Compliance"; public static final String LABEL = "Schema Compliance"; private String definition; private DefinitionContext<?> definitionContext; private String wsdlContextDef; private static Map<String, WsdlContext> wsdlContextMap = new HashMap<String, WsdlContext>(); private static final String SCHEMA_COMPLIANCE_HAS_CLEARED_CACHE_FLAG = SchemaComplianceAssertion.class.getName() + "@SchemaComplianceHasClearedCacheFlag"; public static final String DESCRIPTION = "Validates that the last received message is compliant with the associated WSDL or WADL schema definition. Applicable to SOAP and REST TestSteps."; public SchemaComplianceAssertion(TestAssertionConfig assertionConfig, Assertable assertable) { super(assertionConfig, assertable, false, true, false, true); XmlObjectConfigurationReader reader = new XmlObjectConfigurationReader(getConfiguration()); definition = reader.readString("definition", null); } @Override public void prepare(TestCaseRunner testRunner, TestCaseRunContext testRunContext) throws Exception { super.prepare(testRunner, testRunContext); definitionContext = null; wsdlContextDef = null; // get correct context for checking if cache has been cleared for this run PropertyExpansionContext context = testRunContext.hasProperty(TestCaseRunContext.LOAD_TEST_CONTEXT) ? (PropertyExpansionContext) testRunContext .getProperty(TestCaseRunContext.LOAD_TEST_CONTEXT) : testRunContext; synchronized (context) { if (!context.hasProperty(SCHEMA_COMPLIANCE_HAS_CLEARED_CACHE_FLAG)) { wsdlContextMap.clear(); context.setProperty(SCHEMA_COMPLIANCE_HAS_CLEARED_CACHE_FLAG, "yep!"); } } } protected String internalAssertResponse(MessageExchange messageExchange, SubmitContext context) throws AssertionException { if (messageExchange instanceof WsdlMessageExchange) { return assertWsdlResponse((WsdlMessageExchange) messageExchange, context); } else if (messageExchange instanceof RestMessageExchange) { return assertWadlResponse((RestMessageExchange) messageExchange, context); } throw new AssertionException(new AssertionError("Unknown MessageExchange type")); } @Override protected String internalAssertProperty(TestPropertyHolder source, String propertyName, MessageExchange messageExchange, SubmitContext context) throws AssertionException { return null; } private String assertWadlResponse(RestMessageExchange messageExchange, SubmitContext context) throws AssertionException { WadlDefinitionContext wadlContext = null; try { definitionContext = getWadlContext(messageExchange, context); } catch (Exception e1) { throw new AssertionException(new AssertionError(e1.getMessage())); } WadlValidator validator = new WadlValidator(wadlContext); try { AssertionError[] errors = validator.assertResponse(messageExchange); if (errors.length > 0) { throw new AssertionException(errors); } } catch (AssertionException e) { throw e; } catch (Exception e) { throw new AssertionException(new AssertionError(e.getMessage())); } return "Schema compliance OK"; } private String assertWsdlResponse(WsdlMessageExchange messageExchange, SubmitContext context) throws AssertionException { WsdlContext wsdlContext; try { wsdlContext = (WsdlContext) getWsdlContext(messageExchange, context); } catch (Exception e1) { throw new AssertionException(new AssertionError(e1.getMessage())); } WsdlValidator validator = new WsdlValidator(wsdlContext); try { AssertionError[] errors = validator.assertResponse(messageExchange, false); if (errors.length > 0) { throw new AssertionException(errors); } } catch (AssertionException e) { throw e; } catch (Exception e) { throw new AssertionException(new AssertionError(e.getMessage())); } return "Schema compliance OK"; } private DefinitionContext<?> getWsdlContext(WsdlMessageExchange messageExchange, SubmitContext context) throws Exception { WsdlOperation operation = messageExchange.getOperation(); WsdlInterface iface = operation.getInterface(); String def = PathUtils.expandPath(definition, iface, context); if (StringUtils.isNullOrEmpty(def) || def.equals(iface.getDefinition())) { definitionContext = (iface).getWsdlContext(); definitionContext.loadIfNecessary(); } else { if (definitionContext == null || !def.equals(wsdlContextDef)) { definitionContext = getContext(def, iface.getSoapVersion()); // ( (WsdlContext) definitionContext ).load(); ((WsdlContext) definitionContext).setInterface(iface); wsdlContextDef = def; } } return definitionContext; } private synchronized WsdlContext getContext(String wsdlLocation, SoapVersion soapVersion) throws Exception { if (wsdlContextMap.containsKey(wsdlLocation)) { return wsdlContextMap.get(wsdlLocation); } else { WsdlContext newWsdlContext = new WsdlContext(wsdlLocation, soapVersion); newWsdlContext.load(); wsdlContextMap.put(wsdlLocation, newWsdlContext); return newWsdlContext; } } private DefinitionContext<?> getWadlContext(RestMessageExchange messageExchange, SubmitContext context) throws Exception { RestResource operation = messageExchange.getResource(); RestService service = operation.getService(); if (StringUtils.isNullOrEmpty(definition) || definition.equals(PathUtils.expandPath(service.getDefinition(), service, context))) { definitionContext = service.getWadlContext(); definitionContext.loadIfNecessary(); } else { String def = PathUtils.expandPath(definition, service, context); if (definitionContext == null || !def.equals(wsdlContextDef)) { definitionContext = new WadlDefinitionContext(def); ((WadlDefinitionContext) definitionContext).load(); ((WadlDefinitionContext) definitionContext).setInterface(service); wsdlContextDef = def; } } return definitionContext; } public boolean configure() { String definitionURL = definition; AbstractInterface<?> iface = (AbstractInterface<?>) getAssertable().getInterface(); String orgDef = iface == null ? null : iface.getDefinition(); if (StringUtils.isNullOrEmpty(definitionURL)) { definitionURL = orgDef; } definitionURL = UISupport .prompt("Specify definition url to validate by", "Configure Schema Compliance Assertion", definitionURL); if (definitionURL == null) { return false; } if (!canLoadDefinitionFrom(definitionURL)) { UISupport.showErrorMessage("No valid definition found in " + definitionURL + ". Only WSDL and WADL are supported"); return false; } if (StringUtils.isNullOrEmpty(definitionURL) || definitionURL.equals(orgDef)) { definition = ""; } else { definition = definitionURL; } setConfiguration(createConfiguration()); return true; } private boolean canLoadDefinitionFrom(String definitionURL) { try { new WsdlContext(definitionURL).load(); return true; } catch (Exception e) { try { new WadlDefinitionContext(definitionURL).load(); return true; } catch (Exception e1) { return false; } } } protected XmlObject createConfiguration() { XmlObjectConfigurationBuilder builder = new XmlObjectConfigurationBuilder(); return builder.add("definition", definition).finish(); } protected String internalAssertRequest(MessageExchange messageExchange, SubmitContext context) throws AssertionException { WsdlContext wsdlContext; try { wsdlContext = (WsdlContext) getWsdlContext((WsdlMessageExchange) messageExchange, context); } catch (Exception e1) { throw new AssertionException(new AssertionError(e1.getMessage())); } WsdlValidator validator = new WsdlValidator(wsdlContext); try { AssertionError[] errors = validator.assertRequest((WsdlMessageExchange) messageExchange, false); if (errors.length > 0) { throw new AssertionException(errors); } } catch (AssertionException e) { throw e; } catch (Exception e) { throw new AssertionException(new AssertionError(e.getMessage())); } return "Schema compliance OK"; } public static class Factory extends AbstractTestAssertionFactory { public Factory() { super(SchemaComplianceAssertion.ID, SchemaComplianceAssertion.LABEL, SchemaComplianceAssertion.class); } @Override public String getCategory() { return AssertionCategoryMapping.STATUS_CATEGORY; } @Override public boolean canAssert(Assertable assertable) { try { return super.canAssert(assertable) && assertable.getInterface() instanceof AbstractInterface && ((AbstractInterface<?>) assertable.getInterface()).getDefinitionContext().hasSchemaTypes(); } catch (Throwable e) { SoapUI.logError(e); return false; } } @Override public Class<? extends WsdlMessageAssertion> getAssertionClassType() { return SchemaComplianceAssertion.class; } @Override public AssertionListEntry getAssertionListEntry() { return new AssertionListEntry(SchemaComplianceAssertion.ID, SchemaComplianceAssertion.LABEL, SchemaComplianceAssertion.DESCRIPTION); } } }