How to use map in groovy - groovy

Here is how my script currently looks like -
baseList = readFile('text2.txt').split('\n') as List
def cleanList = []
for (i=0; i < baseList.size; i++) {
if (baseList[i].contains('=')){
cleanList += baseList[i]
}
}
print(cleanList)
This gives following output-
[Pipeline] echo
[version.build=874, version.maintenance=0, version.major=1, version.minor=37]
I want these values to go into another variable called "svnTag"
def svnTag="ccsmp_v_${version.major} ${version.minor} ${version.maintenance} ${version.build}"
So that when I print svnTag, it output something like this-
SVN_TAG=ccsmp_v_1.37.0.846

You are not using a Map, but a List of String, where each element is in the form of <key>=<value>
If you want to parse your file to a Map, you could use something like:
def baseList = readFile('text2.txt').split('\n') as List
def map = [:]
for (el in baseList) {
if (el.contains('=')) {
def parts = el.split('=')
map[parts[0]] = parts[1]
}
}
Then you can use the values from the map with:
def svnTag="ccsmp_v_${map['version.major']} ${map['version.minor']} ${map['version.maintenance']} ${map['version.build']}"
If your file is a valid property file (all lines are in form of key=value), you can use the readProperties step that will create a Properties object for you (that is in fact a Map):
def map = readProperties file: 'text2.txt'

Related

How can I call a function on shell.parse() without first assigning to a variable? for example shell.parse().someFunction()

Right now I'm doing this:
//main.groovy
def func = shell.parse( new File('func.groovy') )
func.someMethod('sdfsdfsdfsdf')
//func.groovy
def someMethod(deploymentFolder) {
return deploymentFolder
}
I want to make the snippet in main.groovy a one-liner but this does not work:
def func = shell.parse( new File('func.groovy') ).someMethod('sdfsdfsdf')
and this doesn't work either:
def func = shell.parse( new File('func.groovy') ) someMethod('sdfsdfsdf')
Is there a way to call a function directly on what shell.parse returns like this?
Edit
I am calling this in a collect call which seems to change things
So this is not working:
list = arrList.collect { file ->
return shell.parse( new File(file) ).someMethod('sdfsdfsdf')
}
someMethod() returns an arrayList. after collect though list seems to contain the right number of nested lists but they are all null.
Yet doing this actually works:
myarr = []
list = arrList.collect { file ->
tempVar = shell.parse( new File(file) )
myarr += tempVar.someMethod('sdfsdfsdf')
}
I'm not sure what the difference is. I thought collect would do the same thing. It seems to almost do the same thing but the lists it concatenates are all null.
Your first attempt there is right and works as suspected:
def shell = new GroovyShell()
println(["func.groovy"].collect{ it as File }.collect{ shell.parse(it).someMethod('sdfsdfsdfsdf') })
// ⇒ [sdfsdfsdfsdf]

How to programmatically build a ForEach input?

I have written a custom JSR223 PostProcessor in order deduplicate a JSON Extractor array, and then build all of the needed variables for a ForEach Controller
import java.util.stream.Collectors;
def previousValuesMatchNrAsString = vars.get("distinctServiceIds_matchNr");
def previousValuesMatchNr = previousValuesMatchNrAsString ? previousValuesMatchNrAsString.toInteger() : 0;
for(i = 1; i <= previousValuesMatchNr; i++) {
vars.remove("distinctServiceIds_" + i);
}
vars.remove("distinctServiceIds_ALL");
vars.remove("distinctServiceIds_matchNr");
def values = vars.get("serviceIds_ALL").split(",");
def newValues = Arrays.stream(values).distinct().collect(Collectors.toList());
def newValuesCount = newValues.size();
def joinesNewValues = String.join(",", newValues);
vars.put("distinctServiceIds_ALL", joinesNewValues);
newValues.eachWithIndex { var, idx -> vars.put("distinctServiceIds_" + (idx + 1), var) };
vars.put("distinctServiceIds_matchNr", newValuesCount.toString());
I have to cleanup variables first, because this JSR223 PostProcessor runs into another ForEach Controller, and then I have to populate distinctServiceIds_ALL, distinctServiceIds_matchNr and all of the indexed variables in order to use distinctServiceIds as "Input variable prefix" for my ForEach Controller.
Although this works, it seems very hacky to me and I wonder if there's some Groovy function, or something else, to do all of that work.
there are many additional methods defined in groovy
as soon as vars contains type of JMeterVariables to remove old vars you could collect required entries from iterator and call remove for each one
the extension groovy methods for iterator could be found in groovy docs
vars.getIterator().findAll{ it.getKey().startsWith('distinctServiceIds_') }.each{
vars.remove(it.getKey())
}
because of groovy it could be simplified to this:
vars.iterator.findAll{ it.key.startsWith('distinctServiceIds_') }.each{
vars.remove(it.key)
}
the same with other generic types: List, Maps, etc
collecting unique values and transforming to map:
def values = [111,222,333,444,444,444,444]
def valMap = values.unique().indexed().collectEntries{k,v-> ['distinctServiceIds_'+(k+1),v] }
vars.putAll(valMap)
so, check groovy jdk extension documentation

Read CSV file and put result in a map using Groovy (without using any external libraries)

I have a CSV file like below :
Sno,Service,Operation,ResponseTimeLimit
1,ProposalService,upsert,50
2,ScheduleService,getReservation,10
3,ScheduleService,bookAppointment,23
I would like to get this structure as the list of map as below :
[
[Sno:"1", Service:"ProposalService",Operation:"upsert",ResponseTimeLimit:"50"],
[Sno:"2",Service:"ScheduleService",Operation:"getReservation",ResponseTimeLimit:"10"],
[Sno:"3",Service:"ScheduleService",Operation:"bookAppointment",ResponseTimeLimit:"23"]
]
I got solution using CSVReader (OpenCSV). But can i do this WITHOUT USING any external references/libraries (like openCSV etc.)?
If the structure of the CSV file will always be the same, you could do it with a Groovy script:
def mapList = []
File csvFile = new File("/path/to/your/file.csv")
csvFile.eachLine { line ->
def parts = line.split(",")
def tmpMap = [:]
tmpMap.putAt("Sno", parts[0])
tmpMap.putAt("Service", parts[1])
// etc.
mapList.add(tmpMap)
}
Below is another way to iterate all rows of the csv file:
def mapList = []
def headers = []
new File("/path/to/your/file.csv").readLines().eachWithIndex { row, rowIndex ->
if (rowIndex == 0) { headers = row.split(',') }
else {
def tmpMap = [:]
def cells = row.split(',').eachWithIndex { cell, cellIndex ->
tmpMap[headers[cellIndex]] = cell
}
mapList.add(tmpMap)
}
}
mapList result:
[[Sno:1, Service:ProposalService, Operation:upsert, ResponseTimeLimit:50], [Sno:2, Service:ScheduleService, Operation:getReservation, ResponseTimeLimit:10], [Sno:3, Service:ScheduleService, Operation:bookAppointment, ResponseTimeLimit:23]]
[Finished in 1.647s]`

Access variable value by its name as String (groovy)

I've done some research but I haven't found a working code for my case. I have two variables named test and test2 and I want to put them in a map in the format [test:valueof(test), test2:valueof(test2)]
My piece of code is the following:
def test="HELLO"
def test2="WORLD"
def queryText = "\$\$test\$\$ \$\$test2\$\$ this is my test"
def list = queryText.findAll(/\$\$(.*?)\$\$/)
def map = [:]
list.each{
it = it.replace("\$\$", "")
map.putAt(it, it)
}
queryText = queryText.replaceAll(/\$\$(.*?)\$\$/) { k -> map[k[1]] ?: k[0] }
System.out.println(map)
System.out.println(queryText)
Output:
Desired output:
"HELLO WORLD this is my test"
I think I need something like map.putAt(it, eval(it))
EDIT
This is the way I get my inputs. the code goes into the 'test' script
The ones on the right are the variable names inside the script, the left column are the values (that will later be dynamic)
You are almost there.
The solution is instead of putting the values into separate variables put them into the script binding.
Add this at the beginning ( remove the variables test and test2):
def test="HELLO"
def test2="WORLD"
binding.setProperty('test', test)
binding.setProperty('test2', test2)
and change this:
{ k -> map[k[1]] ?: k[0] }
to this:
{ k -> evaluate(k[1]) }
It should be very simple if you could use TemplateEngine.
def text = '$test $test2 this is my test'
def binding = [test:'HELLO', test2:'WORLD']
def engine = new groovy.text.SimpleTemplateEngine()
def template = engine.createTemplate(text).make(binding)
def result = 'HELLO WORLD this is my test'
assert result == template.toString()
You can test quickly online Demo
Final working code, thanks to all, in particular to dsharew who helped me a lot!
#input String queryText,test,test2,test3
def list = queryText.findAll(/\$\$(.*?)\$\$/)
def map = [:]
list.each{
it = it.replace("\$\$", "")
map.putAt(it, it)
}
queryText = queryText.replaceAll(/\$\$(.*?)\$\$/) { k -> evaluate(k[1]) }
return queryText

Retrieve value in map by key in Groovy

def text= '''<Rollback> <Kits>
<Kit ServerName='ust1twastool01a'>
<Backup>2016-10-18_20_34-46-_server-21.000.409_client-21.000.407.zip</Backup>
<Backup>2016-10-18_21_57-33-_server-21.000.409_client-21.000.407.zip</Backup>
<Backup>2016-10-19_02_40-03-_server-21.000.413_client-21.000.407.zip</Backup>
<Backup>2016-10-19_13_58-36-_server-21.000.413_client-21.000.407.zip</Backup>
<Backup>2016-10-20_03_14-34-_server-21.000.413_client-21.000.407.zip</Backup>
</Kit>
<Kit ServerName='another_server'>
<Backup>123123.zip</Backup>
<Backup>321321.zip</Backup>
</Kit>
</Kits></Rollback>'''
def xml = new XmlSlurper().parseText(text)
def map = [:]
i = 0
xml.Kits.Kit.each{node->
def list = []
node.Backup.each{kit->
list.add(kit)
}
map.put(node.#ServerName, list)
}
print map // print map with all keys and values
// Somehow, it's not working ...
print map['ust1twastool01a']
def map2 = ['1':["abc","123"], '2':["bcd", "456"]]
print map2['1']
​
I have been annoyed by the above code for almost the day. I don't understand why I can't get value by map['ust1twastool01a'].
I attached a screenshot from a console, it shows that map is not empty but just can't get its value by key. map2 is just control group as it has the similar structure to map string as key and list as value
Use as below:
map.put(node.#ServerName.text(), list)
On a side note, I believe you can simplify the code to just:
def xml = new XmlSlurper().parseText(text)
def map = xml.Kits.Kit.collectEntries { node ->
[ node.#ServerName.text(), node.Backup.collect() ]
}

Resources