Unable to fetch value from JSR223 Sampler - jmeter

I have a JSR223 Sampler in Jmeter with the following code:
import com.jayway.jsonpath.JsonPath
import org.apache.commons.lang3.RandomUtils
import org.apache.jmeter.samplers.SampleResult
def options = JsonPath.read(prev.getResponseDataAsString(), '$.options')
if(options.size() == "1" || options.size() == "2") {
def randomOption = options.get(0)
def code = randomOption.get("code")
vars.put('code1', code)
def values = randomOption.get('values')
def randomValue = values.get(RandomUtils.nextInt(0, values.size()))
def value = randomValue.get('value')
vars.put('valueF', value)
def options2 = JsonPath.read(prev.getResponseDataAsString(), '$.options')
def randomOption2 = options2.get(1)
def code2 = randomOption2.get("code")
vars.put('code2', code2)
def values2 = randomOption2.get('values')
def randomValue2 = values2.get(RandomUtils.nextInt(0, values.size()))
def value2 = randomValue2.get('value')
vars.put('valueF2', value2)
}
else {
vars.put('no loop','Not enterd into loop')
}
vars.put('counts',new
groovy.json.JsonSlurper().parse(prev.getResponseData()).options.size() as
String)
def size = com.jayway.jsonpath.JsonPath.read(prev.getResponseDataAsString(),
'$.options_available')
if (size == []) {
vars.put('size', 'NonConfigurable')
}
else {
vars.put('size', 'Configurable')
}
I am unable to get the value of code1 and valueF , code2 and valueF2 outside of the Sampler. Any possible help is appreciated!

Try amending this line:
def value = randomValue.get('value')
to
def value = randomValue.get('value') as String
Similarly for the "code:
def code = randomOption.get("code") as String
Get used to look into jmeter.log file when you face an issue with JMeter, in the majority of cases it should contain enough troubleshooting information.
If you need further assistance on the topic update it with the full response you're trying to parse. In the meantime:
Groovy: Parsing and Producing JSON
JayWay JSonPath
Groovy is the New Black

JSONArray size should be used by using length(), change in your code
if(options.length() == 1 || options.length() == 2) {

Related

How to upload the payload for a post request randomly in JMeter

Have the following scenario, in my JSON response there is a value called visit which can have either 1 or more than 1 element. So, if the visit have 1 element then the default payload should be sent next POST request or if the visit have more than 1 element then I'm fetching a random value and want to update the payload and sent to the next POST request.
Let me elaborate,
Condition 1 [Have 1 element in the visit section]
Condition 2 [Have more than 1 element in the visit section]
JSON Response for Condition 1
{"studyDTO":{"studyId":191,"studyCode":"test_ispptest2"},"sites":[{"studyId":191,"siteRecid":201,"siteId":"20000"}],"subjects":[{"studyId":191,"siteRecid":201,"subjectRecid":245,"subjectNumber":"20002"}],"states":null,"allVisits":true,"modalities":null,"examDates":null,"series":null,"transferType":null,"sftpLocations":[],"dicomLocations":[],"fileSystemLocations":[],"rawFileSystemLocations":[],"customFolder":null,"folderStructure":null,"customFile":null,"fileStructure":null,"includePS":null}
JSON Response for Condition 2
{"studyDTO":{"studyId":191,"studyCode":"test_ispptest2"},"sites":[{"studyId":191,"siteRecid":16521,"siteId":"11001"}],"subjects":[],"visits":[{"studyId":191,"visitSubmitName":"baseline","visitDisplayName":"Baseline","orderOfDisplay":10},{"studyId":191,"visitSubmitName":"cycle_1","visitDisplayName":"Cycle 1","orderOfDisplay":20}],"sftpLocations":[],"dicomLocations":[],"fileSystemLocations":[],"rawFileSystemLocations":[],"states":null,"modalities":null,"examDates":null,"series":null,"transferType":null,"customFolder":false,"customFile":false,"folderStructure":null,"fileStructure":null,"allSites":false,"allSubjects":true,"allVisits":false,"allStates":false,"allExamDates":false,"allModalities":false,"allSeries":false,"softEditOverride":false,"includePS":false,"includeSR":false,"includeRTStruct":false,"dicomTemplate":null,"errorMessage":null,"successMessage":null}
When I am in Condition 2, fetching random visitSubmitName,visitDisplayName,orderOfDisplay and updating in the payload.
Payload for condition 1:
{"studyDTO":{"studyId":191,"studyCode":"test_ispptest2"},"sites":[{"studyId":191,"siteRecid":201,"siteId":"20000"}],"subjects":[{"studyId":191,"siteRecid":201,"subjectRecid":245,"subjectNumber":"20002"}],"states":null,"allVisits":true,"modalities":null,"examDates":null,"series":null,"transferType":null,"sftpLocations":[],"dicomLocations":[],"fileSystemLocations":[],"rawFileSystemLocations":[],"customFolder":null,"folderStructure":null,"customFile":null,"fileStructure":null,"includePS":null}
Payload for condition 2:
{"studyDTO":{"studyId":191,"studyCode":"test_ispptest2"},"sites":[{"studyId":191,"siteRecid":16521,"siteId":"11001"}],"allSubjects":true,"states":null,"visits":[{"studyId":191,"visitSubmitName":"baseline","visitDisplayName":"Baseline","orderOfDisplay":10}],"modalities":null,"examDates":null,"series":null,"transferType":null,"sftpLocations":[],"dicomLocations":[],"fileSystemLocations":[],"rawFileSystemLocations":[],"customFolder":null,"folderStructure":null,"customFile":null,"fileStructure":null,"includePS":null}
Only change in the payload from condition 1 is,
Solution I have tried so far is created a JSR223 post processer with the following code:
import groovy.json.JsonSlurper
Random rnd = new Random();
def jsonString = prev.getResponseDataAsString();
def jsonConvert = new JsonSlurper();
def object = jsonConvert.parseText(jsonString);
def studyCode = object.studyDTO.studyCode;
def visitS = object.visits.size().toString();
def visitSize = visitS?.isInteger() ? visitS.toInteger() : null
def visitNUM = rnd.nextInt(visitSize);
//def defaultPayload = "{"studyDTO":{"studyId":${studyID},"studyCode":"${study_name}"},"sites":[{"studyId":${studyID},"siteRecid":${siteRecID},"siteId":"${siteID}"}],"subjects":[{"studyId":${studyID},"siteRecid":${siteRecID},"subjectRecid":${subjectRecID},"subjectNumber":"${subjectNumber}"}],"states":null,"allVisits":true,"modalities":null,"examDates":null,"series":null,"transferType":null,"sftpLocations":[],"dicomLocations":[],"fileSystemLocations":[],"rawFileSystemLocations":[],"customFolder":null,"folderStructure":null,"customFile":null,"fileStructure":null,"includePS":null}"
if (visitSize>1) {
def visitSubmitName = object.visits[visitNUM].visitSubmitName
def visitDisplayName = object.visits[visitNUM].visitDisplayName
def orderOfDisplay= object.visits[visitNUM].orderOfDisplay.toString();
//Change the payload with the three value
vars.put('payload',updatedPayload )
}
else {
vars.put('payload',defaultPayload )
}
And the next post sampler,
Error details:
Getting error with the defaultPayload declaration and need the logic for updating the payload.
Is the post sampler declared correctly?
Thanks, in advance
You either need to escape every quotation mark with a backslash
def defaultPayload = "def defaultPayload = '{\"studyDTO\":{\"studyId\":191,\"studyCode\":\"test_ispptest2\"},\"sites\":[{\"studyId\":191,\"siteRecid\":201,\"siteId\":\"20000\"}],\"subjects\":[{\"studyId\":191,\"siteRecid\":201,\"subjectRecid\":245,\"subjectNumber\":\"20002\"}],\"states\":null,\"allVisits\":true,\"modalities\":null,\"examDates\":null,\"series\":null,\"transferType\":null,\"sftpLocations\":[],\"dicomLocations\":[],\"fileSystemLocations\":[],\"rawFileSystemLocations\":[],\"customFolder\":null,\"folderStructure\":null,\"customFile\":null,\"fileStructure\":null,\"includePS\":null}'"
or use single quotation marks instead:
def defaultPayload = '{"studyDTO":{"studyId":191,"studyCode":"test_ispptest2"},"sites":[{"studyId":191,"siteRecid":201,"siteId":"20000"}],"subjects":[{"studyId":191,"siteRecid":201,"subjectRecid":245,"subjectNumber":"20002"}],"states":null,"allVisits":true,"modalities":null,"examDates":null,"series":null,"transferType":null,"sftpLocations":[],"dicomLocations":[],"fileSystemLocations":[],"rawFileSystemLocations":[],"customFolder":null,"folderStructure":null,"customFile":null,"fileStructure":null,"includePS":null}'
No, you either need to use just ${payload} or if you prefer coding go for __groovy() function like ${__groovy(vars.get('payload'),)}
More information:
Apache Groovy - Parsing and producing JSON
Apache Groovy: What Is Groovy Used For?
Guess Dmitri has solved your issue, now coming to the logic. Before that, if I checked your payload for the post request are different. Please try the below code in your JSR223 post-processer.
The json update could be done through json.builder
import groovy.json.JsonSlurper
import groovy.json.JsonBuilder
Random rnd = new Random();
def jsonString = prev.getResponseDataAsString();
def jsonConvert = new JsonSlurper();
def object = jsonConvert.parseText(jsonString);
def studyCode = object.studyDTO.studyCode;
def visitS = object.visits.size().toString();
def visitSize = visitS?.isInteger() ? visitS.toInteger() : null
def visitNUM = rnd.nextInt(visitSize);
def defaultPayload = '{"studyDTO":{"studyId":${studyID},"studyCode":"${study_name}"},"sites":[{"studyId":${studyID},"siteRecid":${siteRecID},"siteId":"${siteID}"}],"subjects":[{"studyId":${studyID},"siteRecid":${siteRecID},"subjectRecid":${subjectRecID},"subjectNumber":"${subjectNumber}"}],"states":null,"allVisits":true,"modalities":null,"examDates":null,"series":null,"transferType":null,"sftpLocations":[],"dicomLocations":[],"fileSystemLocations":[],"rawFileSystemLocations":[],"customFolder":null,"folderStructure":null,"customFile":null,"fileStructure":null,"includePS":null}';
def updatedPayLoad = "";
if (visitSize>1) {
def visitSubmitNameR = object.visits[visitNUM].visitSubmitName
def visitDisplayNameR = object.visits[visitNUM].visitDisplayName
def orderOfDisplayR = object.visits[visitNUM].orderOfDisplay.toString();
def newORDEROFDIS = orderOfDisplayR?.isInteger() ? orderOfDisplayR.toInteger() : null
updatedPayLoad = '{"studyDTO":{"studyId":${studyID},"studyCode":"${study_name}"},"sites":[{"studyId":${studyID},"siteRecid":${siteRecID},"siteId":"${siteID}"}],"allSubjects":true,"states":null,"visits":[{"studyId":${studyID},"visitSubmitName":"","visitDisplayName":"","orderOfDisplay":00}],"modalities":null,"examDates":null,"series":null,"transferType":null,"sftpLocations":[],"dicomLocations":[],"fileSystemLocations":[],"rawFileSystemLocations":[],"customFolder":null,"folderStructure":null,"customFile":null,"fileStructure":null,"includePS":null}'
def newUpdatedPayLoad = jsonConvert.parseText(updatedPayLoad);
def jsonBuilder = new JsonBuilder(newUpdatedPayLoad)
jsonBuilder.content.visits[0].visitSubmitName = visitSubmitNameR
jsonBuilder.content.visits[0].visitDisplayName = visitDisplayNameR
jsonBuilder.content.visits[0].orderOfDisplay = newORDEROFDIS
vars.put('finalPayLoad',jsonBuilder.toPrettyString())
}
else {
vars.put('finalPayLoad',defaultPayload)
}

Possible to have a #NonCPS method read a file in the workspace?

I've written a "vars" function in a Jenkins pipeline script that has to read some XML files from the workspace, parse them, construct a string from pieces found in those files, and return a string.
I initially built it without #NonCPS, and it was pretty painful. I had to null out and reparse the XmlSlurper results several times, including doing that in a loop, as I had to use the "readFile" and "fileExists" pipeline steps. I did get it working, however.
I realized that if I could make this #NonCPS, this could potentially be simpler, but only if I could get file io to work.
This is the original painful version of the function:
def call() {
def pomFileExists = fileExists "pom.xml"
if (!pomFileExists) {
echo "ERROR: No pom file here:"
sh "ls -lt"
return ""
}
def pomFileContent = readFile("pom.xml")
def projectPom = new XmlSlurper().parseText(pomFileContent)
def topArtifactId = projectPom.artifactId.text()
def topVersion = projectPom.version.text()
def topJarPath = "target/" + topArtifactId + ".jar"
projectPom = null
def topJarPathExists = fileExists topJarPath
List targetJars = []
if (topJarPathExists) {
targetJars.add(topJarPath)
}
projectPom = new XmlSlurper().parseText(pomFileContent)
for (int ctr = 0; ctr < projectPom.modules.module.size(); ++ ctr) {
def moduleDir = projectPom.modules.module[ctr].text()
projectPom = null
def modulePomFileContent = readFile(moduleDir + "/pom.xml")
def modulePom = new XmlSlurper().parseText(modulePomFileContent)
def moduleArtifactId = modulePom.artifactId.text()
def moduleVersion = modulePom.version.text()
def jarPath = moduleDir + "/target/" + moduleArtifactId + "-" +
(moduleVersion == "" ? topVersion : moduleVersion) + ".jar"
modulePom = null
def jarPathExists = fileExists jarPath
if (jarPathExists) {
targetJars.add(jarPath)
}
projectPom = new XmlSlurper().parseText(pomFileContent)
}
projectPom = null
def result = targetJars.join(",")
targetJars = null
return result
}
Note that some of the objects I nulled out during the process might not have needed to be nulled out. I sometimes find it hard to tell exactly what objects I need to do that to.
This is my first attempt at a #NonCPS version of this:
#NonCPS
def call(workspaceDir) {
println "workspaceDir[" + workspaceDir + "]"
def pomFile = new File(workspaceDir + "/" + "pom.xml")
if (!pomFile.exists()) {
println "ERROR: No pom.xml file here."
return ""
}
def pom = new XmlSlurper().parse(pomFile)
def topArtifactId = pom.artifactId.text()
def topVersion = pom.version.text()
def topJarPath = workspaceDir + "/target/" + topArtifactId + ".jar"
List targetJars = []
if (new File(topJarPath).exists()) {
targetJars.add(topJarPath)
}
for (int ctr = 0; ctr < pom.modules.module.size(); ++ ctr) {
def moduleDir = pom.modules.module[ctr].text()
def modulePomFile = new File(workspaceDir + "/" + moduleDir + "/pom.xml")
def modulePom = new XmlSlurper().parse(modulePomFile)
def moduleArtifactId = modulePom.artifactId.text()
def moduleVersion = modulePom.version.text()
def jarPath = workspaceDir + "/" + moduleDir + "/target/" + moduleArtifactId + "-" +
(moduleVersion == "" ? topVersion : moduleVersion) + ".jar"
if (new File(jarPath).exists()) {
targetJars.add(jarPath)
}
}
return targetJars.join(",")
}
Note that the call interface is slightly different. For this version, I changed the calling code to pass "pwd()". I also changed the calling code to execute "ls -lt", and it showed the "pom.xml". I also printed the value of "pwd()", and it was identical to the value of "workspaceDir" that I printed in the method.
The result of this is just "ERROR: No pom.xml file here." and an empty string returned. That means the File creation didn't work, so it's not able to see the workspace. I verified that this code works in a standalone shell script.
Is it simply not possible to open files in a #NonCPS method?

Filter tweets in tweepy.StreamListener on_data method

Understand from many articles on stack overflow that the filter method in the tweepy.streaming.stream class uses a logical OR for track and location arguements
so the below will return either tweets from location=USA or with a word ""
streamObj = tweepy.streaming.Stream(oauthObject
,EchoStreamListener(api=apiInstance,
dump_json=args.json,
numtweets=args.numtweets))
keyWordList = ['panthers','falcon']
GEOBOX_USA = [-125,25.1,-60.5,49.1]
streamObj.filter(locations=GEOBOX_USA, track=keyWordList, languages=['en'])
This solution (How to add a location filter to tweepy module
) to check keywords in the on_status method works great, but if i needed to store the entire json variable i think i would have to use the on_data
so changed the on_data (as shown in code below), but get an error:
File "/Library/Python/2.7/site-packages/tweepy/streaming.py", line 294, in _run
raise exception
KeyError: 'text'
-- coding: utf-8 --
from types import *
import tweepy
import json
import argparse
import io
class EchoStreamListener(tweepy.StreamListener):
def __init__(self, api, dump_json=False, numtweets=0):
self.api = api
self.dump_json = dump_json
self.count = 0
self.limit = int(numtweets)
super(tweepy.StreamListener, self).__init__()
# def on_status(self, status):
# if any(keyWord in status.text.lower() for keyWord in keyWordList):
# print status.text
#
# self.count+=1
# return False if self.count == self.limit else True
# else:
# return True # Don't kill the stream
def on_data(self, tweet):
tweet_data = json.loads(tweet) # This allows the JSON data be used as a normal dictionary:
if any(keyWord in tweet_data['text'] for keyWord in keyWordList):
if self.dump_json:
print json.dumps(tweet_data)
saveFile.write(unicode(tweet) + "\n")
self.count+=1
return False if self.count == self.limit else True
else:
print tweet_data['created_at','name','text'].encode("utf-8").rstrip()
def on_error(self, status_code):
print >> sys.stderr, 'Encountered error with status code:', status_code
return True
def get_parser():
parser = argparse.ArgumentParser(add_help=True)
group = parser.add_mutually_exclusive_group(required=True)
group.add_argument(
'-j', '--json',
action='store_true',
help='dump each tweet as a json string'
)
group.add_argument(
'-t', '--text',
dest='json',
action='store_false',
help='dump each tweet\'s text'
)
parser.add_argument(
'-n', '--numtweets',
metavar='numtweets',
help='set number of tweets to retrieve'
)
return parser
if __name__ == '__main__':
oauthObject = tweepy.OAuthHandler(myconsumer_key, myconsumer_secret)
oauthObject.set_access_token(myaccess_key,myaccess_secret)
apiInstance = tweepy.API(oauthObject)
parser = get_parser()
args = parser.parse_args()
streamObj = tweepy.streaming.Stream(oauthObject
,EchoStreamListener(api=apiInstance,
dump_json=args.json,
numtweets=args.numtweets))
keyWordList = ['panthers','falcon']
GEOBOX_USA = [-125,25.1,-60.5,49.1]
saveFile = io.open('/Users/deepaktanna/raw_tweets.json', 'w', encoding='utf-8')
streamObj.filter(locations=GEOBOX_USA, languages=['en'])
saveFile.close()

Dynamically check if a field in JSON is nil without using eval

Here's an extract of the code that I am using:
def retrieve(user_token, quote_id, check="quotes")
end_time = Time.now + 15
match = false
until Time.now > end_time || match
#response = http_request.get(quote_get_url(quote_id, user_token))
eval("match = !JSON.parse(#response.body)#{field(check)}.nil?")
end
match.eql?(false) ? nil : #response
end
private
def field (check)
hash = {"quotes" => '["quotes"][0]',
"transaction-items" => '["quotes"][0]["links"]["transactionItems"]'
}
hash[check]
end
I was informed that using eval in this manner is not good practice. Could anyone suggest a better way of dynamically checking the existence of a JSON node (field?). I want this to do:
psudo: match = !JSON.parse(#response.body) + dynamic-path + .nil?
Store paths as arrays of path elements (['quotes', 0]). With a little helper function you'll be able to avoid eval. It is, indeed, completely inappropriate here.
Something along these lines:
class Hash
def deep_get(path)
path.reduce(self) do |memo, path_element|
return unless memo
memo[path_element]
end
end
end
path = ['quotes', 0]
hash = JSON.parse(response.body)
match = !hash.deep_get(path).nil?

How to return a particular value from a method?

I have this code that tries to return a value from a method:
temp = "123"
return temp
and I have this line that calls the method and assigns the return value:
person_connections = #client.get_person_connections(:id => current_user_id )
but when I try to inspect person_connections, it shows some different object string. Any idea how to return the actual value of the temp variable?
def get_person_connections(options = {})
person_id = options[:id]
path = "/people/id=" + person_id + ":(num-connections)"
query_connections(path, options)
self
end
and
private
def query_connections(path, options={})
fields = options.delete(:fields) || LinkedIn.default_profile_fields
if options.delete(:public)
path +=":public"
elsif fields
path +=":(#{fields.map{ |f| f.to_s.gsub("_","-") }.join(',')})"
end
headers = options.delete(:headers) || {}
params = options.map { |k,v| v.is_a?(Array) ? v.map{|i| "#{k}=#{i}"}.join("&") : "#{k}=#{v}" }.join("&")
path += "?#{params}" if not params.empty?
temp_var = get(path, headers)
hash = JSON.parse(temp_var)
conn = hash["numConnections"]
end
As Samy said in a comment:
In Ruby, the last statement will be returned.
So if we take a look at get_person_connections, we see that the last line is self. What it means is that it returns the instance on which the method was called, #client in this case.
Additional notes: the solution would be to remove self, although if the method is used elsewhere be careful as returning self is often used to allow chaining of methods (though it hardly makes sense to do that on a get method).

Resources