ContributionsMost RecentMost LikesSolutionsSolution for Mockup Request Validation and moreHi folks, I set up a blog to post some issues that may be interested for some of you: SoapUI mockup request validation/verification : http://gilber.vs120026.hl-users.com/wordpress/?p=23 SoapUI mockup asynchronous Response : http://gilber.vs120026.hl-users.com/wordpress/?p=62 Setting up the perfect environment to develop SoapUI mockups: http://gilber.vs120026.hl-users.com/wordpress/?p=44 Cheers, GilbertRe: Change Logfolder WargeneratorIn the folder where wardeployer.sh is called I created a file called "log4.xml", containing the following configuration: <?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE log4j:configuration SYSTEM "log4j.dtd"> <log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/"> <appender name="MeinAppender" class="org.apache.log4j.DailyRollingFileAppender"> <param name="datePattern" value="'.'yyyy-MM-dd_HH-mm" /> <param name="file" value="MyLogFile.log" /> <param name="Append" value="true" /> <layout class="org.apache.log4j.PatternLayout"> <param name="ConversionPattern" value="%d{ISO8601} %-5p [%t] %c: %m%n" /> </layout> </appender> <root> <priority value="INFO" /> <appender-ref ref="MeinAppender" /> </root> </log4j:configuration> That does not affect anything. No "MyLogFile.log" and still these 3 files are created: global-groovy.log soapui.log soapui-errors.log Kind regards, GilbertChange Logfolder WargeneratorHi there, we are deploying Mockups to an applicationserver using wardeployer.sh . At the moment, logfiles are stored at the location, from where we execute wardeployer.sh . Now we want to define the destination of the logfiles. We tried to use add an argument to the java call of com.eviware.soapui.tools.SoapUIProMockAsWarGenerator . We tried: -Dsoapui.logroot=logfolder but it did not work. Do you have an advice please? Thanks in advance, best regards, GilbertRe: [Resolved] Mockup Request and Response ValidationHi Ole, yes, now it works!! Thank you! Here is the whole generic solution for making a mockup validate the requests. The only requirement is that the project uses cached definitions. Note: There is some useless overhead in my solution ("parentclasses"), but acutally that is the structure we use and I'm too lazy to edit it just for posting it. The solution works fine. Call: Copy the following line in the OnRequest-Script: def validator = new validation.Validator( log, context, mockRequest, mockRunner); return validator.validateRequest(); In SoapUI, go to File->Preferences->SoapUI Pro. Define a path to your Script Library, i.e. the directory where you want to store your .groovy files. Inside that directory, create a subdirectory called "validation" and one called "parentclasses". In the "parentclasses" directory: create a file called "OnRequest.groovy" and paste the following content: parentclasses/OnRequest.groovy package parentclasses import com.eviware.soapui.impl.wsdl.mock.WsdlMockRunContext; import com.eviware.soapui.impl.wsdl.mock.WsdlMockRunner; import com.eviware.soapui.impl.wsdl.mock.WsdlMockRequest; import com.eviware.soapui.impl.wsdl.support.wsdl.WsdlContext; import com.eviware.soapui.impl.wsdl.support.wsdl.WsdlValidator; class OnRequest extends ScriptHavingRequest{ protected WsdlMockRunner mockRunner; public OnRequest( log, context, mockRequest, mockRunner){ super( log, context, null, mockRequest); this.mockRunner = mockRunner; } } In the "parentclasses" directory: create a file called "ScriptHavingRequest.groovy" and paste the following content: parentclasses/ScriptHavingRequest.groovy package parentclasses import java.util.UUID; import com.eviware.soapui.impl.wsdl.WsdlTestCasePro; import com.eviware.soapui.impl.wsdl.mock.WsdlMockRequest import com.eviware.soapui.impl.wsdl.mock.WsdlMockResponse import com.eviware.soapui.impl.wsdl.mock.WsdlMockRunContext import com.eviware.soapui.impl.wsdl.mock.WsdlMockOperation import com.eviware.soapui.impl.wsdl.testcase.WsdlTestCaseRunner import com.eviware.soapui.support.XmlHolder import com.eviware.soapui.support.types.StringToObjectMap class ScriptHavingRequest { protected Logger log; protected WsdlMockRunContext context, requestContext; protected WsdlMockRequest mockRequest; protected XmlHolder requestHolder; public ScriptHavingRequest( log_, context_, requestContext_, mockRequest_){ log = log_; context = context_; requestContext = requestContext_; mockRequest = mockRequest_; requestHolder = new XmlHolder( mockRequest.requestContent); } protected initNs( nameSpaceMap){ if( nameSpaceMap != null){ for( ns in nameSpaceMap.entrySet()){ requestHolder.declareNamespace( ns?.key, ns?.value); } } } } In the "validation" directory: create a file called "Validator.groovy" and paste the following content: validation/Validator.groovy package validation import com.eviware.soapui.impl.wsdl.WsdlOperation; import com.eviware.soapui.impl.wsdl.support.wsdl.WsdlValidator; import com.eviware.soapui.impl.wsdl.support.wsdl.WsdlContext; import com.eviware.soapui.impl.wsdl.mock.WsdlMockOperation import com.eviware.soapui.impl.wsdl.panels.mockoperation.WsdlMockRequestMessageExchange; import com.eviware.soapui.impl.wsdl.mock.WsdlMockResult; import com.eviware.soapui.model.iface.MessagePart import org.w3c.dom.Element; import org.w3c.dom.Node; import org.w3c.dom.NodeList; class Validator extends parentclasses.OnRequest{ private final nameSpaceMap = ["soapenv":"http://schemas.xmlsoap.org/soap/envelope/"]; public Validator( log, context, mockRequest, mockRunner){ super( log, context, mockRequest, mockRunner); initNs( nameSpaceMap); } public validateRequest(){ if( context.getMockService().getPropertyValue("requestValidation")?.equals("true")){ def operationElementName = getOperationElementName(); def operationName = operationElementToOperationName(operationElementName); if( operationName == null){ String faultstring = "VALIDATION ERROR: The operation-element '" + operationElementName + "' can not be found. Are request and mockup of the same version?"; log.info( faultstring); return createFaultResponse( faultstring, context.mockService.getMockedOperations().get(0)); } WsdlContext wsdlcontext = context.mockService.getMockedInterfaces()[0].getDefinitionContext(); WsdlValidator validator = new WsdlValidator(wsdlcontext); WsdlMockOperation operation = context.mockService.getMockOperationByName( operationName); WsdlMockRequestMessageExchange msgExchange = new WsdlMockRequestMessageExchange(mockRequest, operation); def errors = validator.assertRequest(msgExchange, /*envelopeOnly*/false); if (errors.length > 0 ){ String validationErrors = "VALIDATION ERRORS: " + errors.collect(){ '\n' + it }; log.info( validationErrors); return createFaultResponse( validationErrors, operation); } log.info("Request Validation OK!"); }else{ log.info("No Request Validation has been performed.") } } private String getOperationElementName(){ Element bodyElement = requestHolder.getDomNode( "//soapenv:Body"); def operationElement = bodyElement.getChildNodes().item(0); while (operationElement && operationElement.nodeType != 1) {//nodeType 1 is Element operationElement = operationElement.nextSibling; } def operationElementName = operationElement.getNodeName(); if( operationElementName.contains(':')){ operationElementName = operationElementName.split(':')[1]; } return operationElementName; } private String operationElementToOperationName(String operationElementName) { for( WsdlOperation wo : context.mockService.getMockedOperations()){ //log.info( "- Operation: " + wo.getName()) for( MessagePart mp : wo.getDefaultRequestParts()){ String partElementName = mp.getProperties().get("partElementName"); if( partElementName.contains('}')){ int idx = partElementName.indexOf('}'); partElementName = partElementName.substring(idx+1, partElementName.length()); } //log.info( " " + partElementName); if( operationElementName.equals(partElementName)){ return wo.getName(); } } } return null; } private WsdlMockResult createFaultResponse( String faultstring){ String content = '''<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"> <soapenv:Body> <soapenv:Fault> <faultcode>Server</faultcode> <faultstring><![CDATA[''' + faultstring + ''']]></faultstring> </soapenv:Fault> </soapenv:Body> </soapenv:Envelope>'''; WsdlMockResult mr = new WsdlMockResult(mockRequest); mockRequest.httpResponse.writer << content; mockRequest.httpResponse.status = 500; log.info( "Validation Errors: " + faultstring); return mr; } private WsdlMockResult createFaultResponse( String faultstring, operation){ String content = '''<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"> <soapenv:Body> <soapenv:Fault> <faultcode>Server</faultcode> <faultstring><![CDATA[''' + faultstring + ''']]></faultstring> </soapenv:Fault> </soapenv:Body> </soapenv:Envelope>'''; WsdlMockResult mr = new WsdlMockResult(mockRequest); mockRequest.httpResponse.writer << content; mockRequest.httpResponse.status = 500; mockRequest.mockOperation = operation; return mr; } } Have Fun! Best regards, GilbertRe: [Resolved] Mockup Request and Response ValidationDear Henrik, should I email you the SoapUI project that contains the case? Safes reconstruction work for you.. Regards, GilbertRe: [Resolved] Mockup Request and Response Validation...but you are right, it is not a good idea to build on the "soapAction" from the SOAP-Header, since it can be an abitrary string. Anyway, to reconstruct the WebUI-bug, please try to hardcode the operationname: WsdlMockOperation operation = context.mockService.getMockOperationByName( "hardcoded_operationname"); Thank you, best regards, GilbertRe: [Resolved] Mockup Request and Response ValidationDear Henrik, the operation is definitely not null, since everything works fine, except of the WebUI! The mock returns the desired responses: a valid answer if the request is valid, a soapfault (as defined in the code above) if the request is invalid. When the mock is deployed, the WebUI behaves like that: everything works normally until a request is invalid, then the WebUI displays the Exception posted above. The mockup itself keeps on running normally and behaves as desired! I think it has something to do with the implementation of the WebUI. I guess that it can not handle that the script-chain is aborted (onrequestscript -> dispatcherscript -> operationscript) and the onrequestscript sends the return. Best regards, GilbertRe: [Resolved] Mockup Request and Response ValidationNow I've solved it that way: in the onRequest script of the MockUp I execute the following code, which works generically for all MockUps that caches its definition: import com.eviware.soapui.impl.wsdl.WsdlOperation import com.eviware.soapui.impl.wsdl.support.wsdl.WsdlValidator; import com.eviware.soapui.impl.wsdl.support.wsdl.WsdlContext; import com.eviware.soapui.impl.wsdl.mock.WsdlMockOperation import com.eviware.soapui.impl.wsdl.panels.mockoperation.WsdlMockRequestMessageExchange; import com.eviware.soapui.impl.wsdl.mock.WsdlMockResult; WsdlContext wsdlcontext = context.mockService.getMockedInterfaces()[0].getDefinitionContext(); WsdlValidator validator = new WsdlValidator(wsdlcontext); String operationName = mockRequest.soapAction.substring(mockRequest.soapAction.lastIndexOf('/') +1).split("#")[1]; WsdlMockOperation operation = context.mockService.getMockOperationByName( operationName); WsdlMockRequestMessageExchange msgExchange = new WsdlMockRequestMessageExchange(mockRequest, operation); def errors = validator.assertRequest(msgExchange, false); if (errors.length > 0 ){ log.info( "returning ValidationError"); String validationErrors = "VALIDATION ERRORS: " + errors.collect(){ '\n' + it }; String content = '''<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"> <soapenv:Body> <soapenv:Fault> <faultcode>Server</faultcode> <faultstring>''' + validationErrors + '''</faultstring> </soapenv:Fault> </soapenv:Body> </soapenv:Envelope>'''; WsdlMockResult mr = new WsdlMockResult(mockRequest); mockRequest.httpResponse.writer << content; mockRequest.httpResponse.status = 200; return mr; } In general it works. There is only one curious bug: We are deploying the mock on a server and using the WebUI (the web interface of the mockup where requests, responses and scriptlog can be viewed). Normally, when I send a request to the mock and it sends the response, the whole conversation can be seen at the WebUI. BUT: when the request is invalid and the script returns the WsdlMockResult, nothing but the scriptlog can be seen and WORSE: the upper third part of the WebUI does not work anymore until redeploying the mockup!!! Instead of showing timestamp, time taken, mockoperation and so on, an Exception appears: java.lang.NullPointerException: com.eviware.soapui.mockaswar.MockAsWarServlet.printMaster(MockAsWarServlet.java:422) com.eviware.soapui.mockaswar.MockAsWarProServlet$MockServletSoapUIProCore.dispatchRequest(SourceFile:128) com.eviware.soapui.mockaswar.MockAsWarServlet.service(MockAsWarServlet.java:190) javax.servlet.http.HttpServlet.service(HttpServlet.java:717) We are using SoapUI-Pro4.5.1. Please could you fix that Exception! It would be an enormous help for us and all other developers who want to use request validation! Thanks in advance, Gilbert FritzRe: [Resolved] Mockup Request and Response ValidationOk, thank you.Re: [Resolved] Mockup Request and Response ValidationOkay, so I'll validate it programatically. We use composite projects with "Cache Definitions = true". Is there an easy way to access these cached definitions? I couldn't find a fitting method in com.eviware.soapui.impl.wsdl.WsdlProject. Thanks in advance, Gilbert