How to read body as string before sending request in gatling - scala

In my performance tests in gatling I'm using ElFileBody to read xml, in which seqNumber will be used in one of the tags, so that each document is unique
<document>
<id>${seqNumber}</id>
</document>
Each unique document I want to then sign, so that I get:
<document>
<id>1</id>
<ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#"><ds:SignedInfo>...</ds:Signature>
</document>
I have tried to use processRequestBody however printing body.toString inside processRequestBody gives me "" so I'm not sure how to get the string value of xml and transform it to add a signature tag.
during(100 seconds) {
forever("seqNumber") {
exec(http("Post New Document")
.post("/document")
.body(ElFileBody("bodies/document.xml"))
.processRequestBody
({ body => {
print(body.toString)
val xml = signatureHelper.sign(body.toString);
StringBody(xml)
}})
.processRequestBody(gzipBody)
.header("Content-Type", "application/xml")
.header("Content-Encoding",
"gzip").check(status.not(400),status.not(500))).exitHereIfFailed
}
}

Related

parsing soap response using Cypress

Facing issues while parsing this response using cypress,
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<soapenv:Header/>
<soapenv:Body>
<p385:summaryOutputArray xmlns:p385="http://dataobject.simulation.com">
<p385:userName>MS</p385:userName>
</p385:summaryOutputArray>
</soapenv:Body>
</soapenv:Envelope>
Using Cypress How to read userName TAG? I can see in the log that whole xml is printed but can't get to the particular tag. Also, while using the function to get to the particular tag to get the value, I am getting null property
Firstly I used this. This is giving error. property reading null
const parser = new DOMParser();
const xmlDOM = parser.parseFromString(quoteResp, 'text/xml');
cy.log('xmlDOM ' + quoteResp.);
cy.wrap(Cypress.$(quoteResp)).then(quoteResp => {
const txt = quoteResp.filter('Body').find('p385:userName').text();
cy.log('value:' + txt);
});
Using this I can see the whole response in logs
then(quoteResp => {cy.log('xmlDOM ' + quoteResp.body);
It's not necessary to wrap the response, just query the xmlDOM like this
const xmlDOM = parser.parseFromString(quoteResp, 'application/xml');
const userName = xmlDOM.querySelector('userName').textContent
expect(userName).to.eq('MS')

constructing request data for SOAP endpoint without WSDL

The endpoint URL looks like this (not an actual url)
https://webservices.abcde.com/ThirdParty/PostData.V55.ashx/ProcessRequest
It does not have a WSDL, and in the documentation, there's a sample request XML.
It's huge. I am adding the first couple lines from it below.
<MESSAGE xmlns:agentnet="http://services.abcde.com/entity/agentnet/v2.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns="http://www.mismo.org/residential/2009/schemas/v32">
<ABOUT_VERSIONS>
<ABOUT_VERSION>
<AboutVersionIdentifier>ClientSystem</AboutVersionIdentifier>
<DataVersionIdentifier>1.0</DataVersionIdentifier>
<DataVersionName>ASDFSFD</DataVersionName>
</ABOUT_VERSION>
</ABOUT_VERSIONS>
<DEAL_SETS>
<DEAL_SET>
<DEALS>
<DEAL>
<PARTIES/>
<SERVICES>
<SERVICE>
<SERVICE_PRODUCT>
<SERVICE_PRODUCT_REQUEST>
<EXTENSION>
<OTHER>
<agentnet:AGENTNET_PRODUCT_REQUEST>
<agentnet:AgentNetServiceType>GET_DATA</agentnet:AgentNetServiceType>
<agentnet:AGENTNET_GET_DATA>
<agentnet:GetRequestType>ACCOUNTS</agentnet:GetRequestType>
</agentnet:AGENTNET_GET_DATA>
</agentnet:AGENTNET_PRODUCT_REQUEST>
...
...
...
...
... (the XML is huge)
With other endpoints, I was able to use a SOAP library like savon to generate the XML payload using a small Ruby Hash(dictionary).
I assume that was possible because those were WSDLs?
Would it be possible to generate the payload the same way by passing only some essential data (for example, GET_DATA and ACCOUNTS in the example), or should I manually construct the XML payload strings manually (maybe using some XML library)?
I really want to avoid manually constructing XML payloads since the code will not be readable and will be hard to work with in general. Is there a way to avoid it?
You can definitively create a Savon client without using the WSDL. I personally like this better because I believe it's more performant.
You have to define endpoint and namespacewhen you create your client, like this fictitious example:
require 'savon'
c = Savon.client(endpoint: "http://www.example.com",
namespace: "urn:ns.example.com",
log: true,
log_level: :debug,
pretty_print_xml: true)
r = c.call(:call,
:message => {
:InquiryParam => [
{"crmParam" => 123,
:attributes! => { "crmParam" => { "name" => "AccountNumber" }}},
{"crmParam" => 456,
:attributes! => { "crmParam" => { "name" => "history" }}}
]
}
)

Gatling extract xpath values error "Namespace prefix 'soap' has not been declared"

Below scenario bringing in me proper SOAP body but I'm not able to extract it's values using xpath expression
The path expression /*/soap:Body/m:NumberToDollarsResponse/m:NumberToDollarsResult/text() I have formed using this website
https://codebeautify.org/Xpath-Tester
val httpConf = http.baseUrl("https://www.dataaccess.com")
val headerXml = Map("Keep-Alive" -> "115", "Content-Type" -> "application/soap+xml; charset=utf-8")
val soapXmlScn = scenario("make First Soap Call")
.exec(
http("Soap API Call With XML")
.post("/webservicesserver/numberconversion.wso")
.headers(headerXml)
.body(StringBody("""<?xml version="1.0" encoding="utf-8"?>
<soap20:Envelope xmlns:soap20="http://www.w3.org/2003/05/soap-envelope">
<soap20:Body>
<NumberToDollars xmlns="http://www.dataaccess.com/webservicesserver/">
<dNum>45</dNum>
</NumberToDollars>
</soap20:Body>
</soap20:Envelope>"""))
.check(status.is(200))
.check(xpath("""//*/soap:Body/m:NumberToDollarsResponse/m:NumberToDollarsResult/text()""").saveAs("doller_value" ))
)
.exec {
session =>
println("doller value >>>> " + session("doller_value").as[String].toString)
session
}
Response body is
<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope">
<soap:Body>
<m:NumberToDollarsResponse xmlns:m="http://www.dataaccess.com/webservicesserver/">
<m:NumberToDollarsResult>forty five dollars</m:NumberToDollarsResult>
</m:NumberToDollarsResponse>
</soap:Body>
</soap:Envelope>
The error shown on console is
12:22:16.880 [ERROR] i.g.c.a.b.SessionHookBuilder$$anon$1 - 'hook-1' crashed with 'j.u.NoSuchElementException: No attribute named 'doller_value' is defined', forwarding to the next one
namespace List needs to be provided to your xpath check as below and my request working fine. Those namespace URLs are mentioned in your SOAP response xml only
.check(xpath("""//soap:Envelope/soap:Body/m:NumberToDollarsResponse/m:NumberToDollarsResult/text()""", List("soap" -> "http://www.w3.org/2003/05/soap-envelope", "m" -> "http://www.dataaccess.com/webservicesserver/")).findAll.saveAs("doller_value" ))

Need help recreating a SOAP request in groovy-wslite

I had issues getting the most basic of actions working, but finally figured it out. You can see what I did here
With that working I'm moving onto the subsequent action and once again running into issues. Here is what the XML SOAP Request looks like which works (generated in PHP)
<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns1="urn:ws.company.com" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:ns2="ws.company.com">
<SOAP-ENV:Header>
<ns2:SessionHeader>
<ns2:sessionId>theLoginSessionID</ns2:sessionId>
</ns2:SessionHeader>
</SOAP-ENV:Header>
<SOAP-ENV:Body>
<ns1:triggerCampaignMessage>
<ns1:campaign>
<ns1:folderName>theFolder</ns1:folderName>
<ns1:objectName>theObject</ns1:objectName>
</ns1:campaign>
<ns1:recipientData>
<ns1:recipient>
<ns1:listName>
<ns1:folderName>theFolder</ns1:folderName>
<ns1:objectName>theObject</ns1:objectName>
</ns1:listName>
<ns1:emailAddress>person#company.com</ns1:emailAddress>
</ns1:recipient>
<ns1:optionalData>
<ns1:name>order_number</ns1:name>
<ns1:value>231</ns1:value>
</ns1:optionalData>
</ns1:recipientData>
</ns1:triggerCampaignMessage>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
The code I am trying to use is this
#Grab(group='com.github.groovy-wslite', module='groovy-wslite', version='0.8.0')
import wslite.soap.*
def client = new SOAPClient('https://company/services/WebService')
def response = client.send(SOAPAction:'https://company/services/WebService/') {
body {
login('xmlns':'urn:ws.company.com') {[
username("username"),
password("password")
]}
}
}
theSession = response.envelope
try {
response = client.send(SOAPAction:'https://company/services/WebService/') {
header {
SessionHeader('xmlns':'urn:ws.company.com') {
sessionId(theSession)
}
}
body {
triggerCampaignMessage('xmlns':'urn:ws.company.com') {[
campaign {[
folderName("theFolder"),
objectName("theObject")
]},
recipientData {[
recipient {[
listName {[
folderName("theFolder"),
objectName("theObject")
]},
emailAddress("person#company.com")
]},
optionalData {[
name("order_number"),
value("1234567890")
]}
]}
]}
}
}
} catch (SOAPFaultException sfe) {
println "fault string :" + sfe.message // faultcode/faultstring for 1.1 or Code/Reason for 1.2
println "envelope :" + sfe.text // prints SOAP Envelope
println "status code :" + sfe.httpResponse.statusCode
println sfe.fault.detail.text()
}
I'm pretty sure that the first send to the login is working since it's the code that works all on it's own and the error message I am receiving is
Unexpected subelement {urn:ws.company.com}emailAddress
So I'm guessing I'm okay up to that point, but can't figure it out. Based on the XML that works can anyone help me get my groovy code to work?
EDIT
Here's the response envelope from the login call
<?xml version="1.0" encoding="UTF-8"?>
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
<soapenv:Body>
<loginResponse xmlns="urn:ws.company.com">
<result>
<sessionId>string here</sessionId>
</result>
</loginResponse>
</soapenv:Body>
</soapenv:Envelope>
The problem may be with theSession = response.envelope which will set theSession to the entire SOAP response from the first call to login. My guess is that you really need to grab a token value from an element within the login response message, for example:
theSession = response.loginResponse.result.sessionId.text()
If you can provide a sample of the result from the call to login I can try to provide a more exact answer.

savon soap attributes

Am trying to query netsuite api for currencies. The following soap request works for me in SOAP UI client. But i am having a hard time trying to get the same working with ruby's savon gem version 0.9.7.
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:urn="urn:messages_2012_2.platform.webservices.netsuite.com" xmlns:urn1="urn:core_2012_2.platform.webservices.netsuite.com">
<soapenv:Header>
<urn:passport>
<urn1:email>xxx#abc.com</urn1:email>
<urn1:password>xxx</urn1:password>
<urn1:account>xxx</urn1:account>
</urn:passport>
</soapenv:Header>
<soapenv:Body>
<urn:getAll>
<urn:record recordType="currency"/>
</urn:getAll>
</soapenv:Body>
</soapenv:Envelope>
Basically i am not able to set the attribute on the urn:record element. The following is not working:
response = client.request :urn, :get_all do
soap.body = { "urn:record" => { :attributes! => { "recordType" => "currency" } } }
end
Please advise.
As explained on http://savonrb.com the key in the attributes! hash has to match the XML tag. You want to write something like this:
response = client.request :urn, :get_all do
soap.body = {'urn:record'=>'',
:attributes!=>{'urn:record'=>{'recordType'=>'currency'}}
}
end
Please let us know whether this solves it for you.
Double-check the raw soap request. :get_all may need to be "getAll" to have savon take you literally; it may be changing it to GetAll
In new versioin of savon you can place :attributes in the local context for the operation tag:
#interaction_client.call(:retrieve_interaction, message: message_hash, :attributes => { 'attachmentInfo' => include_attachments.to_s })
In this case, the attachmentInfo attribute will be placed into the main operation tag linked with operation, in this example this would be the ns:RetrieveInteractionRequest tag.
Please note that the syntax does not contains the exclamation mark.