Convert WebService Response into Json Arrary and Jsobobject using Groovy - groovy

I am testing RESTful webservice using SoapUI. We use Groovy for that.
I am using jsonslurper to parse the response as Object type.
Our reponse is similar to this:
{
"language":[
{
"result":"PASS",
"name":"ENGLISH",
"fromAndToDate":null
},
{
"result":"FAIL",
"name":"MATHS",
"fromAndToDate": {
"from":"02/09/2016",
"end":"02/09/2016"
}
},
{
"result":"PASS",
"name":"PHYSICS",
"fromAndToDate":null
}
]
}
After this, I stuck up on how to.
Get Array (because this is array (starts with -language)
How to get value from this each array cell by passing the key (I should get the value of result key, if name='MATHS' only.)
I could do it using Java, but as just now learning Groovy I could not understand this. We have different keys with same names.

You can just parse it in to a map, then use standard groovy functions:
def response = '''{
"language":[
{"result":"PASS","name":"ENGLISH","fromAndToDate":null},
{"result":"FAIL","name":"MATHS","fromAndToDate":{"from":"02/09/2016","end":"02/09/2016"}},
{"result":"PASS","name":"PHYSICS","fromAndToDate":null}
]
}'''
import groovy.json.*
// Parse the Json string
def parsed = new JsonSlurper().parseText(response)
// Get the value of "languages" (the list of results)
def listOfCourses = parsed.language
// For this list of results, find the one where name equals 'MATHS'
def maths = listOfCourses.find { it.name == 'MATHS' }

Related

DRF how to return multiple datas inside the same serializer

I will try to make my problem as simple as possible:
I have this serializer:
class DatesSerializer(serializers.Serializer):
date = serializers.CharField(max_length=10)
... bunch of stuff and Others serializers
and on my view.py I have this piece of code:
dates = ["2021-05-02", "2021-06-28", "2021-07-02"]
...
for date in dates:
faults = DatesSerializer({
"date":date,
...
})
return Response({"faults":faults.data, status=200})
I receive a response like these:
{
"faults":{
"date":"2021-07-02"
....
}
}
what I wanted was a response like this one
{
"faults":{
"date":"2021-07-02"
....
},
{
"date":"2021-06-28"
....
}, {
"date":"2021-05-02"
....
}
}
I understand that on my loop I'm overwriting my serializer and that's why I just have the last entry, but I have tried to overcome this by adding on a dict and got nowhere since the key will always be the same, and I'm stuck on how to fix this
What you want is not a valid object. You want a list, and this easily can be accomplished in a loop by appending serializer data on each iteration.
res = []
for date in dates:
serializer = DatesSerializer({
"date":date,
...
})
res.append(serializer.data)
return Response({ "faults": res }, status=200)

Remove hyphens from keys in deeply nested map

I posted this question in the Groovy mailing lists, but I've not yet gotten an answer. I was wondering if someone can help here. I am re-posting relevant text from my original question.
I have an input json that’s nested, that is read via a JsonSlurper, and some of the keys have hyphens in them. I need to replace those keys that have hyphens with underscores and convert it back to json for downstream processing. I looked at the JsonGenerator.Options documentation and I could not find any documentation for this specific requirement.
I also looked through options to iterate through the Map that is produced from JsonSlurper, but unfortunately I’m not able to find an effective solution that iterates through a nested Map, changes the keys and produces another Map which could be converted to a Json string.
Example Code
import groovy.json.*
// This json can be nested many levels deep
def inputJson = """{
"database-servers": {
"dc-1": [
"server1",
"server2"
]
},
"discovery-servers": {
"dc-3": [
"discovery-server1",
"discovery-server2"
]
}
}
"""
I need to convert the above to json that looks like the example below. I can iterate through and convert using the collectEntries method which only works on the first level, but I need to do it recursively, since the input json can be an nested many levels deep.
{
"database_servers": {
"dc_1": [
"server1",
"server2"
]
},
"discovery_servers": {
"dc_3": [
"discovery-server1",
"discovery-server2"
]
}
}
Seems like you just need a recursive method to process the slurped Map and its sub-Maps.
import groovy.json.JsonSlurper
JsonSlurper slurper = new JsonSlurper()
def jsonmap = slurper.parseText( inputJson )
Map recurseMap( def inputMap ) {
return inputMap.collectEntries { key, val ->
String newkey = key.replace( "-", "_" )
if ( val instanceof Map ) {
return [ newkey, recurseMap( val ) ]
}
return [ newkey, val ]
}
}
def retmap = recurseMap( jsonmap )
println retmap // at this point you can use output this however you like

Using find{ } on a map where the whole map is evaluated not each element

I created some mixin methods. Code and example below:
URL.metaClass.withCreds = { u, p ->
delegate.openConnection().tap {
setRequestProperty('Authorization', "Basic ${(u + ':' + p).bytes.encodeBase64()}")
}
}
URLConnection.metaClass.fetchJson = {
delegate.setRequestProperty('Accept', 'application/json')
delegate.connect()
def code = delegate.responseCode
def result = new JsonSlurper().parse(code >= 400 ? delegate.errorStream : delegate.inputStream as InputStream)
[
ok : code in (200..299),
body: result,
code: code
]
}
example usage:
new URL("$baseUrl/projects/$name").withCreds(u, p).fetchJson().find {
it.ok
}?.tap{
it.repos = getRepos(it.key).collectEntries { [(it.slug): it] }
}
}
When I dont use find(), my object is, as expected, a map with those 3 elements. When I use find it is a Map.Entry with key ok and value true
which produces this error:
groovy.lang.MissingPropertyException: No such property: ok for class: java.util.LinkedHashMap$Entry
Possible solutions: key
It occured to me when I wrote this post that it was treated the map as an iterable and thus looking at every entry which I have subsequently verified. How do I find on the whole map? I want it.ok because if it's true, I need to carry it forward
There is no such method in Groovy SDK. Map.find() runs over an entry set of the map you call method on. Based on expectation you have defined I'm guessing you are looking for a function that tests map with a given predicate and returns the map if it matches the predicate. You may add a function that does to through Map.metaClass (since you already add methods to URL and URLConnection classes). Consider following example:
Map.metaClass.continueIf = { Closure<Boolean> predicate ->
predicate(delegate) ? delegate : null
}
def map = [
ok : true,
body: '{"message": "ok"}',
code: 200
]
map.continueIf { it.ok }?.tap {
it.repos = "something"
}
println map
In this example we introduced a new method Map.continueIf(predicate) that tests if map matches given predicate and returns a null otherwise. Running above example produces following output:
[ok:true, body:{"message": "ok"}, code:200, repos:something]
If predicate is not met, map does not get modified.
Alternatively, for more strict design, you could make fetchJson() method returning an object with corresponding onSuccess() and onError() methods so you can express more clearly that you add repos when you get a successful response and optionally you create an error response otherwise.
I hope it helps.

Spock: check the query parameter count in URI

I have just started with spock. I have one functionality. where the java function makes an http call. As per functionality, the URI used in http call, must contain "loc" parameter and it should be only once.
I am writing Spock test case. I have written below snippet.
def "prepareURI" () {
given: "Search Object"
URI uri = new URI();
when:
uri = handler.prepareURI( properties) // it will return URI like http://example.com?query=abc&loc=US
then:
with(uri)
{
def map = uri.getQuery().split('&').inject([:]) {map, kv-> def (key, value) = kv.split('=').toList(); map[key] = value != null ? URLDecoder.decode(value) : null; map }
assert map.loc != null
}
}
From above snippet, my 2 tests got passed like
It should be exists
It should not be null
I want to check the count of "loc" query parameter. It should be passed exactly once. With map as above, If I pass "loc" parameter twice, map overrides the old value with 2nd one.
Does any one knows, how to access the query parameters as list, and in list I want to search the count of Strings which starts with "loc"
Thanks in advance.
Perhaps an example would be the best start:
def uri = new URI('http://example.com?query=abc&loc=US')
def parsed = uri.query.tokenize('&').collect { it.tokenize('=') }
println "parsed to list: $parsed"
println "count of 'loc' params: " + parsed.count { it.first() == 'loc' }
println "count of 'bob' params: " + parsed.count { it.first() == 'bob' }
println "count of params with value 'abc': " + parsed.count { it.last() == 'abc' }
prints:
$ groovy test.groovy
parsed to list: [[query, abc], [loc, US]]
count of 'loc' params: 1
count of 'bob' params: 0
count of params with value 'abc': 1
the problem, as you correctly noted, is that you can not put your params into a map if your intent is to count the number of params with a certain name.
In the above, we parse the params in to a list of lists where the inner lists are key, value pairs. This way we can call it.first() to get the param names and it.last() to get the param values. The groovy List.count { } method lets us count the occurences of a certain item in the list of params.
As for your code, there is no need to call new URI() at the beginning of your test as you set the value anyway a few lines down.
Also the with(uri) call is unnecessary as you don't use any of the uri methods without prefixing them with uri. anyway. I.e. you can either write:
def uri = new URI('http://example.com?query=abc&loc=US')
def parsed = uri.query.tokenize('&').collect { it.tokenize('=') }
or:
def uri = new URI('http://example.com?query=abc&loc=US')
uri.with {
def parsed = query.tokenize('&').collect { it.tokenize('=') }
}
(note that we are using query directly in the second example)
but there is not much point in using with if you are still prefixing with uri..
The resulting test case might look something like:
def "prepareURI"() {
given: "Search Object"
def uri = handler.prepareURI( properties) // it will return URI like http://example.com?query=abc&loc=US
when:
def parsed = query.tokenize('&').collect { it.tokenize('=') }
then:
assert parsed.count { it.first() == 'loc' } == 1
}

How can I retrieve the build parameters from a queued job?

I would like to write a system groovy script which inspects the queued jobs in Jenkins, and extracts the build parameters (and build cause as a bonus) supplied as the job was scheduled. Ideas?
Specifically:
def q = Jenkins.instance.queue
q.items.each { println it.task.name }
retrieves the queued items. I can't for the life of me figure out where the build parameters live.
The closest I am getting is this:
def q = Jenkins.instance.queue
q.items.each {
println("${it.task.name}:")
it.task.properties.each { key, val ->
println(" ${key}=${val}")
}
}
This gets me this:
4.1.next-build-launcher:
com.sonyericsson.jenkins.plugins.bfa.model.ScannerJobProperty$ScannerJobPropertyDescriptor#b299407=com.sonyericsson.jenkins.plugins.bfa.model.ScannerJobProperty#5e04bfd7
com.chikli.hudson.plugin.naginator.NaginatorOptOutProperty$DescriptorImpl#40d04eaa=com.chikli.hudson.plugin.naginator.NaginatorOptOutProperty#16b308db
hudson.model.ParametersDefinitionProperty$DescriptorImpl#b744c43=hudson.mod el.ParametersDefinitionProperty#440a6d81
...
The params property of the queue element itself contains a string with the parameters in a property file format -- key=value with multiple parameters separated by newlines.
def q = Jenkins.instance.queue
q.items.each {
println("${it.task.name}:")
println("Parameters: ${it.params}")
}
yields:
dbacher params:
Parameters:
MyParameter=Hello world
BoolParameter=true
I'm no Groovy expert, but when exploring the Jenkins scripting interface, I've found the following functions to be very helpful:
def showProps(inst, prefix="Properties:") {
println prefix
for (prop in inst.properties) {
def pc = ""
if (prop.value != null) {
pc = prop.value.class
}
println(" $prop.key : $prop.value ($pc)")
}
}
def showMethods(inst, prefix="Methods:") {
println prefix
inst.metaClass.methods.name.unique().each {
println " $it"
}
}
The showProps function reveals that the queue element has another property named causes that you'll need to do some more decoding on:
causes : [hudson.model.Cause$UserIdCause#56af8f1c] (class java.util.Collections$UnmodifiableRandomAccessList)

Resources