SoapUI Mock Service Transfer Multiple Nodes - groovy

I am in a pickle.
I feel there is a simple solution to what I want to achieve, but I am at a loss to how to go about it.
Basically, I am standing up some mock Soap services.
I want to echo back an update call with that which is passed in.
My request looks like this:
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
<SOAP-ENV:Header xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"/>
<soap:Body>
<ns2:setEvents xmlns:ns2="http://example.com/eventingservices" xmlns:ns3="http://example.com/eventing/sdo">
<setEventsRequest>
<SystemCode>ABC</SystemCode>
<Event>
<EventTypeCode>01</EventTypeCode>
</Event>
<Event>
<EventTypeCode>04</EventTypeCode>
</Event>
</setEventsRequest>
</ns2:SetEvents>
</soap:Body>
</soap:Envelope>
I then want to simply transfer the list of Events to the response. They have the same attributes as the request.
A typical response, would look like this:
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
<SOAP-ENV:Header xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"/>
<soapenv:Body>
<qu:setEventsResponse xmlns:qu="http:/example.com/eventingServices">
<setEventsResponse>
<Event>
<EventTypeCode>01</EventTypeCode>
</Event>
<Event>
<EventTypeCode>04</EventTypeCode>
</Event>
</setEventsResponse>
</qu:setEventsResponse>
</soapenv:Body>
</soapenv:Envelope>
I tried using the following Groovy script, replacing the Events in the response with ${events}:
def groovyUtils = new com.eviware.soapui.support.GroovyUtils(context)
def holder = groovyUtils.getXmlHolder(mockRequest.requestContent)
def events = String.valueOf(holder.getNodeValues("//Event"))
context.setProperty("events", events);
I also tried the above without doing the string of. To no avail.
Please please help me.
I'll buy you a beer if I can get this damned thing to work!

I suppose that you have a mock service in SOAPUI configured as follows.
Operation with a response similar to:
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
<SOAP-ENV:Header xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/"/>
<soapenv:Body>
<setEventsResponse xmlns="http:/example.com/eventingServices">
<setEventsResponse>
${events}
</setEventsResponse>
</setEventsResponse>
</soapenv:Body>
</soapenv:Envelope>
And on the onRequestScript tab of your mockService you want to have the necessary script to get the <Event> nodes from the request and put it in the response using ${events} property. To do so, I recommend that you can use XmlSlurper as follows:
import groovy.xml.StreamingMarkupBuilder
// parse the request
def reqSlurper = new XmlSlurper().parseText(mockRequest.requestContent)
// find all 'Event' nodes from request
def events = reqSlurper.depthFirst().findAll { it.name() == 'Event' }
// builder to convert the nodes to string
def smb = new StreamingMarkupBuilder()
// concatenate in the string all "<Event>" nodes from request
def eventAsString = ''
events.each{
eventAsString += smb.bindNode(it)
}
// set the property to use in the response
context.setProperty("events", eventAsString);
That's all to make it work :).
Additionally note that there are some mistakes in you xmls. The request in your question is not well formed: </ns2:SetEvents> not close <ns2:setEvents> (note uppercase), and if you want that xmlns:ns2="http://example.com/eventingservices" namespace applies to all childs of <SetEvents> you have to add ns2 to all the child nodes or remove the ns2 to make it default for this subtree:<SetEvents xmlns="http://example.com/eventingservices">` (this applies also for your response)
Hope it helps,

Related

Modifying Soap UI request using groovy

we have a requirement of finding the number of dealers in current country.In the below xml request key-value pair will be varied for every request. Inputs to the soap request will be given in .txt file.Based on the number of inputs in .txt file i need to generate key-value pair xml tags dynamically.
**Format of Input.txt**
1.key1=Fruit,value1=Carrot,Key2=Vegetable,value2=Carrot
2.key1=Vegetable,value1=Potato
3.key1=Fruit,value1=Apple,key2=Fruit,value2=Orange,key3=Fruit,value3=Mango
SoapUI Request
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:web="http://www.webserviceX.NET">
<soapenv:Header/>
<soapenv:Body>
<web:GetCitiesByCountry>
<web:CountryName>Ind</web:CountryName>
<web:queryParameters>
<web:key>Fruits</web:key>
<web:value>Mango</web:value>
</web:queryParameters>
<web:queryParameters>
<web:key>Vegetables</web:key>
<web:value>Carrot</web:value>
</web:queryParameters>
</web:GetCitiesByCountry>
</soapenv:Body>
</soapenv:Envelope>
You say you have the reading of the input records sorted, so I've just put some records in a map for demonstration purposes. Then, if your request payload starts off looking like:
<soap:Envelope xmlns:soap="w3.org/2003/05/soap-envelope">
<soap:Header/>
<soap:Body>
<web:GetCitiesByCountry xmlns:web="webserviceX.NET">
<web:CountryName>hello</web:CountryName>
</web:GetCitiesByCountry>
</soap:Body>
</soap:Envelope>
You can loop through your input records and append them to the request:
import groovy.xml.XmlUtil
// Assuming the input document has been read into a HashMap
def map = ['Fruits': 'Banana',
'Vegetable': 'Potato'
]
// Get testStep by it's name
def testStep = context.testCase.getTestStepByName('soapRequest')
// Parse the request
def xml = new XmlSlurper().parseText(testStep.getPropertyValue('request'))
// Loop through the map and append the key/value pairs
xml.Body.appendNode {
map.each {k, v ->
Parameters {
Key(k)
Value(v)
}
}
}
// Check the output
log.info(XmlUtil.serialize( xml ))
// Update the request
testStep.setPropertyValue('request',groovy.xml.XmlUtil.serialize( xml ))
Afterwards, your request will look like:
<soap:Envelope xmlns:soap="w3.org/2003/05/soap-envelope">
<soap:Header/>
<soap:Body>
<web:GetCitiesByCountry xmlns:web="webserviceX.NET">
<web:CountryName>hello</web:CountryName>
</web:GetCitiesByCountry>
<Parameters>
<Key>Fruits</Key>
<Value>Banana</Value>
</Parameters>
<Parameters>
<Key>Vegetable</Key>
<Value>Potato</Value>
</Parameters>
</soap:Body>
</soap:Envelope>
As you said you need to add
<Parameters> <Key>key1</Key> <Value>Value1</Value> </Parameters>
dynamically while executing groovy script
So inside your groovy script in a variable
xmlValue="<Parameters> <Key>key1</Key> <Value>Value1</Value> </Parameters>"
testRunner.testCase.setPropertyValue(xmlNodes,xmlValue)
So now your dynamic xml is in testCase property. So inside your xml where you want to place it
you can place this code
<web:CountryName>${#TestCase#xmlValue}</web:CountryName>
This way it will get added. If you pass it null,then nothing will be added in your xml.
There's some good technical solutions here, but if you buy a SoapUI license, you'll be able to access the data driven test functionality, which does exactly what you want right out of the box. No groovy scripts required.

Groovy script in SOAPUI to insert new tags in Soap request

I am using SOAP UI pro. My requirement is that, I need to write a groovy script to add few tag and elements to the previously processed request.
Below is my initial request and its name is "Certify Request" in my SOAP project
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:pay="http://www.abcdefgh.com/eai/xsd/custom/Payout.xsd">
<soapenv:Header/>
<soapenv:Body>
<pay:request>
<pay:header>
<pay:applicationID>TANDEM001</pay:applicationID>
<pay:hostname>WUNS1</pay:hostname>
<pay:timestamp>${=new java.text.SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ").format(new Date())}</pay:timestamp>
<pay:correlationID>${#TestCase#CorrelationID}</pay:correlationID>
</pay:header>
<pay:input>
<pay:payoutTransactionDetails>
<pay:transferDetails>
<pay:sendCountryCode>${#TestCase#sendCountryCode}</pay:sendCountryCode>
<pay:sendAmount>
<pay:currencyCode>${#TestCase#sendCurrencyCode}</pay:currencyCode>
<pay:value multiplier="100">${#TestCase#sendAmount}</pay:value>
<pay:fxRate multiplier="100">${#TestCase#senderfxRate}</pay:fxRate>
</pay:sendAmount>
<pay:receiveCountryCode>${#TestCase#receiveCountryCode}</pay:receiveCountryCode>
<pay:receiveAmount>
<pay:currencyCode>${#TestCase#receiveCurrencyCode}</pay:currencyCode>
<pay:value multiplier="100">${#TestCase#receiveAmount}</pay:value>
<pay:fxRate multiplier="100">${#TestCase#receiverfxRate}</pay:fxRate>
</pay:receiveAmount>
<pay:overallFX multiplier="100000000">${#TestCase#OverallFX}</pay:overallFX>
</pay:transferDetails>
</pay:payoutTransactionDetails>
</pay:input>
</pay:request>
</soapenv:Body>
</soapenv:Envelope>
I would like to add below tags in it under " " tag:
<pay:senderAgent>
<pay:agentID>1760289</pay:agentID>
<pay:accountNumber>036526952</pay:accountNumber>
</pay:senderAgent>
So that my target request will be like below: (and it's name should be Initiate Request )
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:pay="http://www.abcdefgh.com/eai/xsd/custom/Payout.xsd">
<soapenv:Header/>
<soapenv:Body>
<pay:request>
<pay:header>
<pay:applicationID>TANDEM001</pay:applicationID>
<pay:hostname>WUNS1</pay:hostname>
<pay:timestamp>${=new java.text.SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ").format(new Date())}</pay:timestamp>
<pay:correlationID>${#TestCase#CorrelationID}</pay:correlationID>
</pay:header>
<pay:input>
<pay:payoutTransactionDetails>
<pay:senderAgent>
<pay:agentID>${#TestCase#senderAgentID}</pay:agentID>
<pay:accountNumber>${#TestCase#senderAgentAcountNumber}</pay:accountNumber>
</pay:senderAgent>
<pay:transferDetails>
<pay:sendCountryCode>${#TestCase#sendCountryCode}</pay:sendCountryCode>
<pay:sendAmount>
<pay:currencyCode>${#TestCase#sendCurrencyCode}</pay:currencyCode>
<pay:value multiplier="100">${#TestCase#sendAmount}</pay:value>
<pay:fxRate multiplier="100">${#TestCase#senderfxRate}</pay:fxRate>
</pay:sendAmount>
<pay:receiveCountryCode>${#TestCase#receiveCountryCode}</pay:receiveCountryCode>
<pay:receiveAmount>
<pay:currencyCode>${#TestCase#receiveCurrencyCode}</pay:currencyCode>
<pay:value multiplier="100">${#TestCase#receiveAmount}</pay:value>
<pay:fxRate multiplier="100">${#TestCase#receiverfxRate}</pay:fxRate>
</pay:receiveAmount>
<pay:overallFX multiplier="100000000">${#TestCase#OverallFX}</pay:overallFX>
</pay:transferDetails>
</pay:payoutTransactionDetails>
</pay:input>
</pay:request>
</soapenv:Body>
</soapenv:Envelope>
I referred the solution on this link https://community.smartbear.com/t5/SoapUI-Pro/Using-Groovy-to-insert-new-tag-into-request-Need-help-with/m-p/124928#M28773 , however not able to succeed.
Thanks for your help
You could use a property inside a groovy script
def senderAgent=" <pay:senderAgent> ....... </pay:senderAgent>"
testRunner.testCase.setPropertyValue("Variable",senderAgent)
and then place that variable inside the XML
<pay:payoutTransactionDetails>
${#TestCase#senderAgent}
<pay:transferDetails>
So you have stored the xml value in groovy and then expanded that inside the XML

Query parameter in twilio action url

I am trying to pass data through twilio's Record verb action url. When there are two or more query string parameters it fails, but when there is only one it succeeds.
Succeeds:
var response = '<Response><Say>STUFF TO SAY</Say><Pause length="1"/><Record maxLength="3600" timeout="30" action="/service/training/call/recording?test1=test&test2=test"></Record></Response>';
Fails:
var response = '<Response><Say>STUFF TO SAY</Say><Pause length="1"/><Record maxLength="3600" timeout="30" action="/service/training/call/recording?test1=test"></Record></Response>';
error:
Error on line 1 of document : The reference to entity "test2" must end with the ';' delimiter.
Is there a way I can pass the data through the query string or do I have to resort to using url parameters? "/service/training/call/recording/test/test
Twilio support got back to me. Here is their response.
The fix is to replace the '&' in your code with it's valid-XML replacement - '&'. So your TwiML would look like this:
<?xml version="1.0" encoding="UTF-8"?>
<Response>
<Say>STUFF TO SAY</Say>
<Pause length="1"/>
<Record maxLength="3600" timeout="30" action="/service/training/call/recording?test1=test&test2=test">
</Record>
</Response>

how to pull the parameter from cdata response and use it in another request using groovy in soapUi

This is my response from soapUI
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<soap:Body>
<SearchAirFaresResponse xmlns="http://www.sample.com/xchange">
<SearchAirFaresResult>
<![CDATA[
<FareSearchResponse>
<MasterDetails>
<CurrencyCode>INR</CurrencyCode>
<RecStNo>1</RecStNo>
<SessionID>5705b1a6-95ac-486c-88a1f90f85e57590</SessionID>
</MasterDetails>
</FareSearchResponse>
]]>
</SearchAirFaresResult>
</SearchAirFaresResponse>
</soap:Body>
</soap:Envelope>
How to extract SessionID element which is inside CDATA using groovy script and use it in another request like
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<soap:Body>
<xch:GetMoreFares>
<xch:sGetMoreFare>
<![CDATA[
<MoreFlights>
<MasterDetails>
<NoOfResult Index="1">40</NoOfResult>
<BranchId>1</BranchId>
<SessionId>5705b1a6-95ac-486c-88a1f90f85e57590</SessionId>
</MasterDetails>
<Journey>DOM</Journey>
<ResponseType>XML</ResponseType>
<SearchType>OW</SearchType>
</MoreFlights>
]]>
</xch:sGetMoreFare>
</soap:Body>
</soap:Envelope>
3.I have been searching lot but didnt get the right one,and also am new to groovy script using soapUi , pls guide me stepwise procedure in soapUi to implement .
To do so you can use a Groovy testStep, inside it get the SOAP testStep where you've the response with desired sessionID and use a XmlSlurper to parse the response and get the CDATA value. Note that XmlSlurper treat CDATA as String so you've to parse it again. Finally save the returned value as a TestSuite or TestCase level (in the example I use TestCase):
// get your first testStep by its name
def tr = testRunner.testCase.getTestStepByName('Test Request')
// get your response
def response = tr.getPropertyValue('response')
// parse the response and find the node with CDATA content
def xml = new XmlSlurper().parseText(response)
def cdataContent = xml.'**'.find { it.name() == 'SearchAirFaresResponse' }
// XmlSlurper treat CDATA as String so you've to parse
// its content again
def cdata = new XmlSlurper().parseText(cdataContent.toString())
// finally get the SessionID node content
def sessionId = cdata.'**'.find { it.name() == 'SessionID' }
// now save this value at some level (for example testCase) in
// order to get it later
testRunner.testCase.setPropertyValue('MySessionId',sessionId.toString())
Then change a bit your second testStep to use property expansion to get the MySessionId property in your second request as ${#TestCase#MySessionId}:
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<soap:Body>
<xch:GetMoreFares>
<xch:sGetMoreFare>
<![CDATA[
<MoreFlights>
<MasterDetails>
<NoOfResult Index="1">40</NoOfResult>
<BranchId>1</BranchId>
<SessionId>${#TestCase#MySessionId}</SessionId>
</MasterDetails>
<Journey>DOM</Journey>
<ResponseType>XML</ResponseType>
<SearchType>OW</SearchType>
</MoreFlights>
]]>
</xch:sGetMoreFare>
</soap:Body>
</soap:Envelope>
This is also most similar to albciff's answer, but with little variant (using reusable closure to parse).
Here is the Script Assertion for the first request step. This will avoid additional groovy script step in the test case.
Please follow the appropriate comments inline:
Script Assertion:
/**
* This is Script Assertion for the first
* request step which extracts cdata from response,
* then sessionId from extracted cdata. And
* Assigns the value at test case level, so that
* it can be used in the rest of the test steps of
* the same test case.
* However, it is possible to store the sessionId
* at Suite level as well if you want use the sessionId
* across the test cases too.
*
* */
/**
* Closure to search for certain element data
* input parameters
* xml data, element name to search
**/
def searchData = { data, element ->
def parsedData = new XmlSlurper().parseText(data)
parsedData?.'**'.find { it.name() == element} as String
}
//Assert the response
assert context.response, "Current step response is empty or null"
//Get the cdata part which is inside element "SearchAirFaresResult"
def cData = searchData(context.response,'SearchAirFaresResult')
//Assert CDATA part is not null
assert cData, "Extracted CDATA of the response is empty or null"
//Get the SessionID from cdata
def sessionId = searchData(cData, 'SessionID')
//Assert sessionId is not null or empty
assert sessionId, "Session Id is empty or null"
log.info "Session id of response $sessionId1"
//Set the session to test case level custom property
//So, that it can be used for the rest of the steps
//in the same test case
context.testCase.setPropertyValue('SESSION_ID', sessionId)
In the following test steps, you can use the saved SESSION_ID in the following ways:
If the following step is request step (REST, SOAP, HTTP, JDBC etc), then use property expansion ${#TestCase#SESSION_ID} like <SessionId>${#TestCase#SESSION_ID}</SessionId>
If the following step is groovy script, then use one of the below:
context.expand('${#TestCase#SESSION_ID}') or
context.testCase.getPropertyValue('SESSION_ID') or
testRunner.testCase.getPropertyValue('SESSION_ID')

Updating a WsdlRequest value via SoapUI Pro

I want to update a WsdlRequest parameter values at runtime using groovy.
Say I have a WsdlRequest that contains two parameters: name, address. I’d like to pass to this WsdlRequest the values I would like the request to have prior to creating a WsdlSubmit instance. I know the base code is this:
WsdlProject project = new WsdlProject()
WsdlInterface iface = WsdlInterfaceFactory.importWsdl(project, wsdl, true)[0]
WsdlOperation operation = (WsdlOperation) iface.getOperationAt(3)
WsdlRequest request = operation.addNewRequest(requestName)
request.setRequestContent (requestContent);
The requestContent is the soapxml in a String format. Is there a good way to insert my values (say I want name value to be ‘Test’ and address value to be ‘Example’ for the request)? I’d rather not store the xml as a string and update this if I already have that information when I generate the request.
Here is an example of the xml:
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:data="http://test.com">
<soapenv:Header/>
<soapenv:Body>
<data:updateFieldName>
<fieldId>?</fieldId>
<!--Optional:-->
<newFieldId>?</newFieldId>
</data:updateFieldName>
</soapenv:Body>
</soapenv:Envelope>
Prior to creating the WsdlRequest, I have created a groovy object that contains the values I want to fill into the above soap xml message. Let's say this object states the fieldId = 10 and the newFieldRequest = 15. I a not sure how to pass those values into the request. Is there a way to do this with the SoapUI API? I do have a pro license also.
You can use an XMLHolder to parse your xml, and the you can use setNodeValue(xpath, value) to specify the value for this node, in your case this looks like:
import com.eviware.soapui.support.XmlHolder
// your request content
def requestContent = '<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:data="http://test.com">'+
'<soapenv:Header/>'+
'<soapenv:Body>'+
'<data:updateFieldName>'+
'<fieldId>?</fieldId>'+
'<newFieldId>?</newFieldId>'+
'</data:updateFieldName>'+
'</soapenv:Body>'+
'</soapenv:Envelope>'
// parse it as xml bean
def requestXml = new XmlHolder(requestContent)
// set your node values
requestXml.setNodeValue("//*:fieldId","10");
requestXml.setNodeValue("//*:newFieldId","15");
Then to get the xml content as string again you can use getXml() method as follows:
WsdlRequest request = ...
// to set in your request use getXml()
request.setRequestContent (requestXml.getXml());
For more info you can take a look at XMLHolder api documentation
There is also another way to do this without groovy script; using properties. You can add a properties in for example your TestCase and then use it directly in your TestStep request like this:
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:data="http://test.com">
<soapenv:Header/>
<soapenv:Body>
<data:updateFieldName>
<fieldId>${#TestCase#yourProperty}</fieldId>
<newFieldId>${#TestCase#anotherProperty}</newFieldId>
</data:updateFieldName>
</soapenv:Body>
</soapenv:Envelope>
If you're interested in this take a look at: Working with properties and property expansion
EDIT BASED ON COMMENT:
I write a whole example with your code and xml holder using a public wsdl due you can try and get the result without the NPE and compare with yours to check what is going on:
import com.eviware.soapui.impl.wsdl.WsdlProject
import com.eviware.soapui.impl.wsdl.WsdlInterface
import com.eviware.soapui.impl.WsdlInterfaceFactory
import com.eviware.soapui.impl.wsdl.WsdlOperation
import com.eviware.soapui.impl.wsdl.WsdlRequest
import com.eviware.soapui.support.XmlHolder
wsdl = "http://www.webservicex.net/geoipservice.asmx?WSDL"
WsdlProject project = new WsdlProject()
WsdlInterface iface = WsdlInterfaceFactory.importWsdl(project, wsdl, true )[0]
WsdlOperation operation = (WsdlOperation) iface.getOperationByName( "GetGeoIP" )
WsdlRequest request = operation.addNewRequest("Request")
def defaultRequest = operation.createRequest(true)
def xmlHolder = new XmlHolder(defaultRequest)
xmlHolder.setNodeValue("//*:IPAddress","127.0.0.1");
request.setRequestContent (xmlHolder.getXml());
Hope this helps,
Below is the groovy script for the following:
Update all WSDL Definitions in the project.
Recreate all requests to updated ones.
Takes backup of old requests.
import static com.eviware.soapui.impl.wsdl.actions.iface.UpdateInterfaceAction.recreateRequests
import static com.eviware.soapui.impl.wsdl.actions.iface.UpdateInterfaceAction.recreateTestRequests
project = testRunner.testCase.testSuite.project; //get the project reference
def ifaceList = project.getInterfaceList(); //get all the interfaces present in the project in a list
//start a loop for number of interfaces
for(int i = 0; i < project.getInterfaceCount() ; i++)
{
def iface = project.getInterfaceAt(i);
def url = iface.definition;
iface.updateDefinition( url, true); //updateDefinition(String url , Boolean createRequests)
//The above part updates the definition
//The part below recreates the requests based on updated wsdl definition
//syntax -
//recreateRequests( WsdlInterface iface, boolean buildOptional, boolean createBackups, boolean keepExisting, boolean keepHeaders )
recreateRequests(iface,true,true,true,true);
recreateTestRequests(iface,true,true,true,true);
}
//End of Script//

Resources