How to store Id values from response in soapui - web-services

I have to add 3 records in Soap UI request as below:
<soapenv:Envelope>
<soapenv:Header/>
<soapenv:Body>
<wor:AddValues>
<wor:User>
<data:userid>${Properties1#UserID}</data:userid>
</wor:User>
<data:ValuesList>
<data:Value>
<data:Desc>${Properties1#Desc1}</data:Desc>
<data:Details>${Properties1#Detail1}</data:Details>
</data:Value>
<data:Value>
<data:Desc>${Properties1#Desc2}</data:Desc>
<data:Details>${Properties1#Detail2}</data:Details>
</data:Value>
<data:Value>
<data:Desc>${Properties1#Desc3}</data:Desc>
<data:Details>${Properties1#Detail3}</data:Details>
</data:Value>
</data:ValuesList>
</wor:AddValues>
</soapenv:Body>
</soapenv:Envelope>
After completion this will generate unique ID for each value added.
The response would look like below:
<s:Envelop>
<s:Body>
<AddUserValueResult>
<a:ValuesList>
<a:Value>
<a:Id>2501</a:Id>
<a:Desc>Desc1</a:Desc>
<a:Details>Detail1</a:Details>
</a:Value>
<a:Value>
<a:Id>2502</a:Id>
<a:Desc>Desc2</a:Desc>
<a:Details>Detail2</a:Details>
</a:Value>
<a:Value>
<a:Id>2503</a:Id>
<a:Desc>Desc3</a:Desc>
<a:Details>Detail3</a:Details>
</a:Value>
</a:ValuesList>
</AddUserValueResult>
</s:Body>
</s:Envelop>
Using groovy script I want to use the properties Desc1 & Details1,
compare it with response and if it matches then get the ID of that record and store the ID generated in response in another Property Id1.
Continue same for other two records.
Can you please help me to achieve this?
Thanks in Advance!

Here is what to be done one in order to be able to compare the data from request and response:
Create an object model, so that both request and response can be transformed into list of objects, and then compare.
Extract the required data from request / response and build the object list
Need to consider a fact that the both request and response has list of data / values, and it may come in any random order. So, the object should be comparable.
In this case, Script Assertion can be used for comparison without any additional test step. So, add the script assertion to your Soap Request test step.
Here is the script:
/**
* This is script assertion
* Reads both request and response
* Builds the object list, so that both can be compared
**/
//Object Model, req / resp is transformed into this model
#groovy.transform.Canonical
#groovy.transform.Sortable
class Model {
String desc
String details
}
//Closure to retrieve the data element of user choice from xml
def searchData = { data, element ->
def parsedData = new XmlSlurper().parseText(data)
parsedData.'**'.findAll{it.name() == element}
}
//Closure to build the object list of above provided Model class
def buildData = { list, desc, details ->
def objects = []
list.each { item ->
objects << new Model(desc: item."$desc", details: item."$details")
}
objects
}
//Assert if the request and response are non-empty
assert context.rawRequest, "Request is empty or null"
assert context.response, "Response is empty or null"
//Get the Value elements from both request and response
def reqValues = searchData(context.rawRequest, 'Value')
def respValues = searchData(context.response, 'Value')
//Build the Model object list for both request and response and sort them to be able to compare
def reqObjectList = buildData(reqValues, 'Desc', 'Details' ).sort()
def resObjectList = buildData(respValues, 'Desc', 'Details' ).sort()
//Log the above
log.info "Value objects from request: ${reqObjectList.toString()}"
log.info "Value objects from response: ${resObjectList.toString()}"
//Finally, compare the data from both request and response
assert reqObjectList == resObjectList, "Data is not matching"
//Now set the Ids at test case level custom properties
respValues.eachWithIndex { value, index ->
log.info "Id${index+1} : ${value.Id as String}"
context.testCase.setProperty("Id${index+1}", "${value.Id as String}")
}
Now you can use ${#TestCase#Id1} etc.. where ever you need those values.
Note that : it will save those ids if an only if both ValuesList are matched.
You may quickly try it out from Demo till comparing request and response valueslist

Related

Retrieve value from Map<String, dynamic> after getting it from an API

I'm trying to get a value from an API and usually I get it through a list and just use an index and the String to get the info I need (e.g. data[index]["String"]), however this API sends a Map<String, dynamic> and I used the key to retrieve part of the Map (data["key"]}) but I am trying to be more specific in the value. Is there a way to get the exact value, like data["key"]["String"]?
You can use json.decode on your data
Example :
var response = await /* httpcall */
var data = json.decode(response.body);
Depending on the structure of your response you might have to change the field that you json encode, but at least you can now use data['foo']['bar']

how to save a xml list from response to a csv file in JMeter

one of my tests uses a Loop Controller, CSV Data Set Config and an If Controller to iterate through a csv list to do one request with several parameters defined in an csv file.
I want to change this testcase to use a list of parameters that i get from an GET response in an xml format.
for example using this xml list: http://www.w3schools.com/xml/cd_catalog.xml
now i want to iterate through all < TITLE > values.
i tried to save the response with the 'Save Responses to a file' Listener and then use a BeanShell Listener to read the file and transform it to a csv list which contains only the < TITLE > values. but i'm not sure how to to this transformation part in the BeanShell Listener.
import org.apache.jmeter.services.FileServer;
import org.apache.commons.io.FileUtils;
File xmlFile = new File(FileServer.getFileServer().getBaseDir()+"/resources/data/csv/response1.xml", "UTF-8");
String fileData = FileUtils.readFileToString(xmlFile);
fileData = fileData.replaceAll("<?xml version="1.0" encoding="UTF-8"?>", "");
fileData = fileData.replaceAll("<CATALOG>", "");
//...
FileUtils.writeStringToFile(xmlFile, fileData);
/*
f = new FileOutputStream(FileServer.getFileServer().getBaseDir()+"/resources/data/csv/parameterlist.csv", true);
p = new PrintStream(f);
p.println(fileData);
p.close();
f.close();
*/
there must be some solution using regex, xpath or XSL transformation on all < TITLE > elements or is there an easier way that i didn't thought of?
found a different and easier method that works for my purpose:
Get Request to get the xml list.
add XPath Extractor
Reference Name: 'titles'
XPAth query: '//title'
ForEach Controller
Input variable prefix: 'titles'
Output variable name: 'title'

SoapUI REST mock service give errors when mocking to handle dynamic responses depending on request values (But the same method works for SOAP mocks)

I was trying to mock the following REST web-service using soapUI
Sample Request:
<Request>
<HistoricTxn>
<reference>E1</reference>
<method>txn</method>
</HistoricTxn>
</Request>
SampleResponse1
<Response>
<reason>ACCEPTED</reason>
<status>1</status>
<time>10:12</time>
</Response>
SampleResponse2
<Response>
<information>Failure on invalid request details</information>
<reason>fails Luhn check</reason>
<status>3</status>
<time>10:15</time>
</Response>
Usually I use this kind of a groovy script to evaluate the request and out put a dynamic response. (When using soapUI to mock SOAP web services)
groovy Script:
def groovyUtils = new com.eviware.soapui.support.GroovyUtils(context);
def holder = groovyUtils.getXmlHolder(mockRequest.getRequestContent());
def reference = holder.getNodeValue("//reference");
if(reference == "Success"){
return "SampleResponse1";
} else {
return "SampleResponse2";
}
Unfortunately when I try to hit a request to this REST mock service end point it returns an error.
Error:
com.eviware.soapui.impl.wsdl.mock.DispatchException: Failed to
dispatch using script; java.lang.NullPointerException: Cannot invoke
method getRequestContent() on null object
I understand that the error message says getRequestContent() has returned a null value and because of that I am getting this exception. But the same works with the SOAP mock services, with out returning null values or causing exceptions. Appreciate any workarounds to overcome this issue.
I just figured that mockRequest.getRequestContent() returns null for all the POST, PUT, DELETE requests sent to REST web-services mocked using soapUI (version 5.2.1)
def holder = groovyUtils.getXmlHolder(mockRequest.getRequestContent());
Since the above (RequestContent) returns null, soap UI can not evaluate the value of the following tag.
def reference = holder.getNodeValue("//reference");
SoapUIOfficial References for this bug in soapUI(version 5.2.1):
https://community.smartbear.com/t5/SoapUI-NG/SoapUI-5-0-requestContent-is-null-for-Rest-Mock-service/td-p/40458
https://community.smartbear.com/t5/SoapUI-NG/Mock-Service-mockRequest-requestContent-is-NULL-HTTP-PUT/td-p/42138
I just found a workaround to overcome the aforesaid bug in soapUI(version 5.2.1).
By this point it is clear to me that I can use mockRequest.getRequest().getReader().readLine() script to read a single line in the request body. (though mockRequest.getRequestContent() returned a null object)
I would simply access the request body using the following groovy script.
def requestBody="";
try {
while ((line = mockRequest.getRequest().getReader().readLine()) != null){
requestBody = requestBody+line;
}
} catch (Exception e) {
log.error("exception:"+e)
}
def groovyUtils = new com.eviware.soapui.support.GroovyUtils(context);
def holder = groovyUtils.getXmlHolder(requestBody);
def reference = holder.getNodeValue("//reference");
According to the above script, it will have to read the request body line by line and then merge all the lines to have the whole request body.
Since the request body is not null anymore following script can evaluate the value inside reference tag.
def reference = holder.getNodeValue("//reference");
eventually i was able to mock my REST mock service with dynamic responses according to following conditions.
if(reference == "Success"){
return "SampleResponse1";
} else {
return "SampleResponse2";
}
Hope you could save a lot of time by following this method.

Query parameters for GET requests using Akka HTTP (formally known as Spray)

One of the features of Akka HTTP (formally known as Spray) is its ability to automagically marshal and unmarshal data back and forth from json into case classes, etc. I've had success at getting this to work well.
At the moment, I am trying to make an HTTP client that performs a GET request with query parameters. The code currently looks like this:
val httpResponse: Future[HttpResponse] =
Http().singleRequest(HttpRequest(
uri = s"""http://${config.getString("http.serverHost")}:${config.getInt("http.port")}/""" +
s"query?seq=${seq}" +
s"&max-mismatches=${maxMismatches}" +
s"&pam-policy=${pamPolicy}"))
Well, that's not so pretty. It would be nice if I could just pass in a case class containing the query parameters, and have Akka HTTP automagically generate the query parameters, kind of like it does for json. (Also, the server side of Akka HTTP has a somewhat elegant way of parsing GET query parameters, so one would think that it would also have a somewhat elegant way to generate them.)
I'd like to do something like the following:
val httpResponse: Future[HttpResponse] =
Http().singleRequest(HttpRequest(
uri = s"""http://${config.getString("http.serverHost")}:${config.getInt("http.port")}/query""",
entity = QueryParams(seq = seq, maxMismatches = maxMismatches, pamPolicy = pamPolicy)))
Only, the above doesn't actually work.
Is what I want doable somehow with Akka HTTP? Or do I just need to do things the old-fashioned way? I.e, generate the query parameters explicitly, as I do in the first code block above.
(I know that if I were to change this from a GET to a POST, I could probably to get it to work more like I would like it to work, since then I could get the contents of the POST request automagically converted from a case class to json, but I don't really wish to do that here.)
You can leverage the Uri class to do what you want. It offers multiple ways to get a set of params into the query string using the withQuery method. For example, you could do something like this:
val params = Map("foo" -> "bar", "hello" -> "world")
HttpRequest(Uri(hostAndPath).withQuery(params))
Or
HttpRequest(Uri(hostAndPath).withQuery(("foo" -> "bar"), ("hello" -> "world")))
Obviously this could be done by altering the extending the capability of Akka HTTP, but for what you need (just a tidier way to build the query string), you could do it with some scala fun:
type QueryParams = Map[String, String]
object QueryParams {
def apply(tuples: (String, String)*): QueryParams = Map(tuples:_*)
}
implicit class QueryParamExtensions(q: QueryParams) {
def toQueryString = "?"+q.map{
case (key,value) => s"$key=$value" //Need to do URL escaping here?
}.mkString("&")
}
implicit class StringQueryExtensions(url: String) {
def withParams(q: QueryParams) =
url + q.toQueryString
}
val params = QueryParams(
"abc" -> "def",
"xyz" -> "qrs"
)
params.toQueryString // gives ?abc=def&xyz=qrs
"http://www.google.com".withParams(params) // gives http://www.google.com?abc=def&xyz=qrs

How do I configure mime types in a grails Spock test?

Grails 2.3.10.
How can I configure the available mime types for content type negotiation in a Grails Spock test?
When I try to tell the controller to produce JSON content, it seems to want to return an HTTP 406 error. I send in the Accept header in my test code; but, the parser is not able to match it because HTML is the only MIME type that's configured.
My use case...
I have implemented a controller action using the Grails respond method which can return a JSON response. When I hit the endpoint using a REST API call, I am able to get back JSON output (even if no Accept header is specified).
The controller code:
#Transactional(readOnly = true)
class MyObjectController {
static allowedMethods = [save: 'POST']
static responseFormats = ['json']
def myService
#Transactional
def save(MyObject obj) {
obj.validate()
if (obj.hasErrors()) {
respond obj.getErrors(), [status: BAD_REQUEST]
}
myService.addNewCustomer(obj)
respond obj, [formats: responseFormats]
}
}
And my test code:
#TestFor(MyObjectController)
class MyObjectControllerSpec extends Specification {
def setup() {
}
def cleanup() {
}
void "test save - json success"() {
given:
def myObj = new MyObject()
controller.myService= Mock(MyObjectService)
when:
request.addHeader "Accept", "application/json"
controller.save(individual)
then:
response.status == HttpStatus.CREATED.value()
response.text == "{}" //.text is giving me an empty string
response.json.x == x //.json throws an exception (parsing an empty string)
}
}
I have verified in the debugger that obj has a valid value and that the respond method is invoked on the last line of the controller action.
What I am finding is that inside the Grails ResponseMimeTypesApi class, the DefaultAcceptHeaderParser is getting constructed with only the HTML mime type. Even though the JSON accept header is being read correctly, the DefaultAcceptHeaderParser isn't able to understand it because no mime types are configured.
How do I control the mime types that get sent to ResponseMimeTypesApi in my unit test spec?
Edit
I have also tried setting the response.format property, as suggested in this answer; but, to no avail.
If you assign a value to request.json that will set the content type. You can also set the content type explicitly with something like request.contentType = 'application/json' or request.contentType = JSON_CONTENT_TYPE. For a list of the content type constants available in your unit tests see the "Testing Mime Type Handling" section under http://grails.org/doc/latest/guide/testing.html#unitTestingControllers.
Another resource to look at is the unit tests at https://github.com/grails/grails-core/blob/4f8d1a605cde60a4a00021102959578dae8bc5a8/grails-test-suite-web/src/test/groovy/org/codehaus/groovy/grails/web/binding/json/JsonBindingSpec.groovy and https://github.com/grails/grails-core/blob/801d507cf3fec5866baa14f6d6b0acd05aa5fb56/grails-test-suite-web/src/test/groovy/org/codehaus/groovy/grails/web/binding/xml/XmlBindingSpec.groovy.
I hope that helps.
EDIT:
To clarify...
I mentioned assigning a value to request.json. The value you assign to that of course is JSON, not the content type. Like this...
request.json = '''
{
"name": "Douglas", "age": "42"
}
'''
When you do that, the content type gets set automatically.
I found that I could write the test that I wanted by converting from a unit to an integration test.
Move the test to the /integration path.
Change the test spec to extend IntegrationSpec
#Autowire the class under test instead of using #TestFor:
Set controller.response.format = 'json' and call controller.request.addHeader 'Accept', 'application/json'